JavaScript中this指向

执行期上下文

函数执行时(准确来说,是在函数发生预编译的前一刻),会创建一个执行期上下文的内部对象。一个执行期上下文定义了一个函数执行时的环境。

每调用一次函数,就会创建一个新的上下文对象,他们之间是相互独立且独一无二的。当函数执行完毕,它所产生的执行期上下文会被销毁。

参考链接:https://www.cnblogs.com/chenyingjie1207/p/9966036.html

this

解析器在调用函数每次都会向函数内部传递进一个隐含的参数,这个隐含的参数就是 this,this 指向的是一个对象,这个对象我们称为函数执行的 上下文对象。

函数内 this 的指向【非常重要】

根据函数的调用方式的不同,this 会指向不同的对象:

  • 1.以函数的形式(包括普通函数、定时器函数、立即执行函数)调用时,this 的指向永远都是 window。比如fun();相当于window.fun();
  • 2.以方法的形式调用时,this 指向调用方法的那个对象
  • 3.以构造函数的形式调用时,this 指向实例对象
  • 4.以事件绑定函数的形式调用时,this 指向绑定事件的对象
  • 5.使用 call 和 apply 调用时,this 指向指定的那个对象

针对第 1 条的举例

function fun() {
    console.log(this);
    console.log(this.name);
}

var obj1 = {
    name: 'smyh',
    sayName: fun,
};

var obj2 = {
    name: 'vae',
    sayName: fun,
};

var name = '全局的name属性';

//以函数形式调用,this是window
fun(); //可以理解成 window.fun()

打印结果:

Window
全局的name属性

上面的举例可以看出,this 指向的是 window 对象,所以 this.name 指的是全局的 name。

第 2 条的举例

function fun() {
    console.log(this);
    console.log(this.name);
}

var obj1 = {
    name: 'smyh',
    sayName: fun,
};

var obj2 = {
    name: 'vae',
    sayName: fun,
};

var name = '全局的name属性';

//以方法的形式调用,this指向调用方法的对象
obj2.sayName();

打印结果:

{name: "vae", sayName: ƒ}
vae

上面的举例可以看出,this 指向的是 对象 obj2 ,所以 this.name 指的是 obj2.name。

箭头函数中 this 的指向

对于普通函数,遵循第2条规则,sayName中的this指向的调用该方法的对象,即obj

var name = "Tom";
var obj = {
    name: "Jerry",
    sayName: function() {
        console.log(this.name);
    }
};
obj.sayName();		//Jerry

如果我们把普通函数改为箭头函数呢?

var name = "Tom";
var obj = {
    name: "Jerry",
    sayName: () => {
        console.log(this.name);
    }
};
obj.sayName();		//Tom

需要注意的是,箭头函数中的 this 指向不遵循上面所有的规则,而是指向定义该函数所在的作用域指向的对象,作用域是指函数内部,obj是不产生作用域的,所以这里sayName中的this指向的是最外层的对象,也就是window对象。

注意:箭头函数使用call或apply调用时,不能改变this的指向

var name = "Tom";
let obj = {
    name: "Jerry",
    sayName: () => {
        console.log(this.name);
    }
};
let obj1 = {
    name: "Spike"
}
obj.sayName.call(obj1);		//这里的this还是指向的window,所以打印的是Tom

例2:

function Person() {
    this.num = 0;
    setTimeout(function() {
        //这里的this指向的是window对象,和Person构造函数中的this并不相同
        this.num++;
    },1000)
}
var p = new Person();

如果想让setTimeout里的this指向Person构造函数中的this,可以这么写:

function Person() {
    var that = this;
    that.num = 0;
    setTimeout(function() {
        that.num++;
    },1000);
}
var p = new Person();

如果使用用箭头函数,就可以很简单地改写为:

function Person() {
    this.num = 0;
    setTimeout(() => {
        this.num++;
    },1000);
}
var p = new Person();

改变函数内部的 this 指向

JS 专门为我们提供了一些方法来改变函数内部的 this 指向。详见下一篇文章中的 call()、apply()、bind() 方法。

转载于:https://github.com/qianguyihao/Web