看代码写输出,
关于 this 指向、闭包、箭头函数、IIFE 的题:
var name = "global";
var obj = {
name: "obj",
getName: function () {
return function () {
return this.name;
};
},
getNameArrow: function () {
return () => this.name;
},
};
// 1
console.log(obj.getName()());
// 2
console.log(obj.getNameArrow()());
// 3
var count = (function () {
var n = 0;
return function () {
n++;
return n;
};
})();
console.log(count(), count(), count());
// 4
var funcs = [];
for (var i = 0; i < 3; i++) {
funcs.push(function () {
return i;
});
}
console.log(funcs[0](), funcs[1](), funcs[2]());
// 5
var a = 10;
function foo() {
console.log(this.a);
}
var obj2 = { a: 20, foo: foo };
var bar = obj2.foo;
obj2.foo();
bar();
参考答案
点击展开
obj.getName()()→'global'。getName() 返回了一个普通函数,这个函数是被单独调用的(()()),调用时没有挂在任何对象上,所以 this 指向全局(非严格模式下是 window),this.name 就是 var name = ‘global’。这是经典的”this 丢失”。obj.getNameArrow()()→'obj'。箭头函数没有自己的 this,它捕获的是定义时外层的 this。getNameArrow 是被 obj.getNameArrow() 调用的,此时外层 this 是 obj,箭头函数就锁定了 obj,所以拿到 ‘obj’。这正是①和②的对比考点。count(), count(), count()→1 2 3。IIFE 立即执行,内部 n 通过闭包被返回的函数持续引用,不会被销毁。每次调用累加,所以是 1 2 3(注意从左到右求值)。funcs[0](<>), funcs[1](<>), funcs[2](<>)→3 3 3。var 没有块级作用域,三个函数共享同一个 i。循环结束后 i 已经变成 3,三个闭包读的都是这同一个 i,所以全是 3。 (如果把 var 改成 let,每次迭代是独立作用域,结果就是 0 1 2——常见追问。)obj2.foo()→20;bar()→10。this 取决于调用方式:obj2.foo() 是方法调用,this 是 obj2,输出 20;bar() 把函数取出来单独调用,this 指向全局,输出 var a = 10。
总结:this 看谁在调用(箭头函数除外,它看定义位置);闭包让内部变量存活下来;var 无块级作用域会让循环闭包翻车。
加载中...