关于setTimeout函数中的this指向问题

  • Post author:
  • Post category:其他


为什么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;