this到底指向谁
关于this指向的问题,有一种广泛流行的说法就是: 谁调用它,this就指向谁。
也就是说,this 的指向是在调用时确定的。这么说没有太大的问题,可是并不全面。事实上,调用函数时会创建属于函数自身的执行上下文。执行上下文的调用创建阶段会确定this的指向,因此我们得出一个结论: this的指向是根据调用函数时的执行上下文所动态确定的
一:全局环境下的this
function fn1(){
console.log(this)
}
function fn2(){
'use strict'
console.log(this)
}
fn1() //window
fn2() //undefined
这种情况是在全局环境下,调用this,非严格模式下指向window对象,严格模式下是undefined。我们再来对全局环境的this进行一下变化考察。
const obj = {
num:10,
fn1:function(){
console.log(this);
console.log(this.num);
}
}
let fn2 = obj.fn1;
fn2() //window undefined
这里我们是把obj里的函数fn1赋值给了全局变量下的fn2,调用fn2的时候,就是window对象在进行调用,所以打印this指向了window,打印this.num输出undefined,是因为在全局环境下没有num这个变量,所以输出undefined。就相当于下面代码的调用:
console.log(this) // window
console.log(window.num) // undefined
我们再来进行一下变化考察
const obj = {
num:10,
fn1:function(){
console.log(this);
console.log(this.num);
}
}
obj.fn1()
//{num: 10, fn: ƒ}
//10
上面代码中fn1函数是被obj对象调用,所以会指向obj对象。所以可得:在执行函数时,如果函数是被上一级对象所调用,this就指向上一级对象,否则就指向全局环境
二:上下文对象调用中的this
const o1 = {
text: 'o1',
fn: function () {
return this.text;
},
};
const o2 = {
text: 'o2',
fn: function () {
return o1.fn();
},
};
const o3 = {
text: 'o3',
fn: function () {
var fn = o1.fn;
return fn();
},
};
console.log(o1.fn()); // o1
console.log(o2.fn()); // o1
console.log(o3.fn()); // undefine
三:bind/call/apply 改变 this 指向
他们都是用来改变相关函数 this 指向的,但是 call/apply 是直接进行相关函数调用;bind 不会执行相关函数,而是返回一个新的函数,这个新的函数已经自动绑定了新的 this 指向,开发者需要手动调用即可。
const target = {};
fn.call(target, 'arg1', 'arg2');
// 相当于:
const target = {};
fn.apply(target, ['arg1', 'arg2']);
// 相当于:
const target = {};
fn.bind(target, 'arg1', 'arg2')();
四:构造函数和 this
function Foo() {
this.bar = 'Lucas';
}
const instance = new Foo();
console.log(instance.bar); // Lucas
答案将会输出 Lucas。但是这样的场景往往伴随着下一个问题:new 操作符调用构造函数,具体做了什么? 以下供参考:
- 创建一个新的对象;
- 将构造函数的 this 指向这个新对象;
- 为这个对象添加属性、方法等;
- 最终返回新对象。
需要指出的是,如果在构造函数中出现了显式 return 的情况,那么需要注意分为两种场景:
function Foo() {
this.user = 'Lucas';
const o = {};
return o;
}
const instance = new Foo();
console.log(instance.user); // undefined
function Foo() {
this.user = 'Lucas';
return 1;
}
const instance = new Foo();
console.log(instance.user); // Lucas
结论:如果构造函数中显式返回一个值,且返回的是一个对象,那么 this 就指向这个返回的对象;如果返回的不是一个对象,那么 this 仍然指向实例。
六:箭头函数中的 this 指向
箭头函数使用 this 不适用以上标准规则,而是根据外层(函数或者全局)上下文来决定。
const foo = {
fn: function () {
setTimeout(function () {
console.log(this);
});
},
};
foo.fn(); // window
这道题中,this 出现在 setTimeout() 中的匿名函数里,因此 this 指向 window 对象。如果需要 this 指向 foo这个 object 对象,可以巧用箭头函数解决:
const foo = {
fn: function () {
setTimeout(() => {
console.log(this);
});
},
};
foo.fn(); // {fn:f}