引言:
关于 this 有一个非常重要的思想要知道,this
不是写在哪里就被绑定在哪里,而是代码运行的时候才被绑定。也就是说如果一个函数中存在this
,那么this
到底指什么取决于这个函数以什么样的方式被调用,下面常见的几个场景:
一、全局环境
在全局环境中,this 指向全局对象,在浏览器中是window,n
ode环境中是 global
二、普通函数调用
对于直接调用普通函数(非箭头函数)
来说,不管函数在什么地方被调用,this
一定是全局对象
function f1() {
console.log(this.name);
}
function f2() {
f1();
}
var name = '小红';
f1(); // 小红
f2(); // 小红
三、对象方法调用
当函数被作为对象方法调用时,谁调用了函数,谁就是 this
const obj = {
name: '小明',
f1: function () {
console.log(this.name);
},
f2() {
console.log(this.name);
}
}
obj.f1(); // 小明
obj.f2(); // 小明
四、构造函数
在构造函数中,this 指向 new 创建的对象
function F1() {
this.name = '小红';
}
const f1 = new F1();
f1.name; // '小红'
五、箭头函数函数
箭头函数中没有this,所以箭头函数中的 this
与包裹箭头函数的第一个普通函数的 this保持一致
function a() {
return () => {
return () => {
console.log(this)
}
}
}
console.log(a()()()) // window
因为包裹箭头函数的第一个普通函数是 a
,所以此时的 this
是 window
。另外对箭头函数使用 bind
这类函数是无效的。
六、call/apply/bind调用
bind、apply、call都是用来改变函数的this对象指向的,第一个参数都是this要指向的对象
var xw = {
name: "小王",
say: function() {
console.log(this.name);
}
};
var xh = {
name: "小红"
};
xw.say(); // 小王
xw.say.call(xh); // 小红
xw.say.apply(xh); // 小红
xw.say.bind(xh)(); // 小红
可以看出,三种方法都能改变this的指向,用xw的say方法来显示xh的数据,但是有什么区别呢?
- 直接写xw.say.bind(xh)是不会输出结果的,call和apply都是对函数的直接调用,而bind方法返回的仍然是一个函数,因此需要用()来进行调用才行;
- call可以传入多个参数;
- apply只能传入两个参数,所以其第二个参数往往是作为数组形式传入
优先级:
当多个规则同时出现的时候,就会根据优先级的来决定 this 的最终指向,优先级如下:
new > bind,apply,call > 对象方法 > 普通方法
箭头函数的 this 一旦被绑定,就不会再被任何方式所改变。
总结:
- 对于直接调用普通
函数
,this
一定是全局对象 - 对于
obj.foo()
来说,我们只需要记住,谁调用了函数,谁就是this
,所以在这个场景下foo
函数中的this
就是obj
对象 - 在构造函数中,this 指向 new 创建的对象,
this
不会被任何方式改变 - 箭头函数中没有this,所以箭头函数中的
this
只取决包裹箭头函数的第一个普通函数的this
- 使用call/apply/bind方法时,this指向第一个参数