为什么setTimeout函数的延迟执行函数中this指向window,但是延迟执行函数是箭头函数this指向obj?
根据下面的两点原因解释,foo和foo2中的this都指向obj,但是其中setTimeout,它的第二个this指向应该是window,至于为什么foo2的this也指向obj,原因在于foo2中setTimeout的第一个参数是箭头函数,箭头函数没有自己的this,它的this跟父级的this指向一致,都指向obj。
var obj = {
name: 'name',
foo: function () {
console.log(this); // Object {name: "name"}
setTimeout(function () {
console.log(this); // Window
}, 1000);
},
foo2: function () {
console.log(this); // Object {name: "name"}
setTimeout(() => {
console.log(this); // Object {name: "name"}
}, 2000);
}
}
原因在于:
setTimeout函数挂载在window对象下,《javascript高级程序设计》中写道:“超时调用的代码都是在全局作用域中执行的,因此函数中的this在非严格模式下指向window对象,在严格模式下是undefined。
将setTimeout调用环境下的this称为第一个this,将延迟执行函数中的this称为第二个this,此时有结论:
1.第一个this的指向是需要根据上下文来确定的,默认为window;
2.第二个this的指向是固定的,就是指向window;
对于结论1的证明:
1.函数作为方法调用还是构造函数调用,this是不同的
function Foo() {
this.value = 42;
this.method = function() {
// this 指向全局对象
alert(this) // 输出window 第二个this
alert(this.value); // 输出:undefined 第二个this
};
setTimeout(this.method, 500); // this指向Foo的实例对象 第一个this
}
new Foo();
2.在外层添加一层代码,第二个this可以访问到window上的value
var value=33;
function Foo() {
this.value = 42;
this.method = function() {
// this 指向全局对象
alert(this) // 输出window 第二个this
alert(this.value); // 输出:33 第二个this
};
setTimeout(this.method, 500); // 这里的this指向Foo的实例对象 第一个this
}
new Foo();
可以看出method方法中的this指向window,因为可以输出外层value的值。
那么为什么setTimeout中的this指向的就是Foo的实例对象呢?
在setTimeout中的this是可以根据上下文而改变的。
接下来验证一下:
function method() {
alert(this.value); // 输出 42 第二个this
}
function Foo() {
this.value = 42;
setTimeout(this.method, 500); // 这里this指向window 第一个this
}
Foo();
Foo()执行的时候,method方法放到外层,此时setTimeout中的this.method中的this指向window,因此可以调用到method方法。method方法中的this仍然指向window,当Foo()执行的时候,对window.value进行了赋值this.value=42,此时输出42.
结论:
setTimeout中的第一个this的指向是根据上下文来确定的,默认指向window。
对于结论2的证明:
1.直接使用
setTimeout('console.log(this)',1); //Window
2.在一个对象中调用
var obj = {
say:function(){
setTimeout('console.log(this)',1);
}
}
obj.say() //Window
3.将执行的代码换成匿名函数
var obj = {
say:function(){
setTimeout(function(){
console.log(this);
},1);
}
}
obj.say() //Window
4.将执行的代码换成函数引用
function talk(){
console.log(this);
}
var obj = {
say:function(){
setTimeout(talk,1);
}
}
obj.say() //Window
结论:
setTimeout中的延迟执行函数中的this指向window;