引言:this的指向,这是一个面试经典问题,也是 ES5中众多坑中的一个
- this 是执行上下文中的一个属性,它指向最后一次调用这个方法的对象。在实际开发中,this 的指向可以通过四种调用模式来判断。
this和函数类型的关系
- 普通函数
- 箭头函数
- bind,call和apply重新指定后的函数
this的指向与是否开启严格模式的关系
- 非严格模式:执行环境中没有设置this,则指向window
- 严格模式:执行环境中没有设置this,则保持undefined
this与环境的关系(非严格模式下,没有谁调用)
- Node: globalThis
- 浏览器: window;
接下来就让我们结合例子开始正式学习this的指向吧 (· _ ·)
一、普通函数
1、使用 new 关键字创建的函数,this会指向被创建出来的实例
构造函数中的this会指向
new出来的实例对象
// 浏览器环境
function F(name, age) {
this.name = name;
this.age = age;
console.log(this); // {name: 'tom', age: 18}
};
let f = new F('tom', 18);
2、没有使用 new 关键字的函数,取决于调用方式(谁调用指向谁)
Object.func()对象调用的,指向这个对象func()非严格模式下,直接调用,指向window异步调用非严格模式下,指向window
// 浏览器环境,非严格模式
// 定义一个对象
let obj = {
// obj对象内的name
name: 'tom',
speak() {
console.log(this.name);
},
verdict() {
console.log(this === window);
},
};
// window上的name
var name = 'jack';
// 将函数赋值给a
let a = obj.speak;
// 输出obj的name
obj.speak(); // tom
// 输出window上的name
a(); // jack
// 输出window上的name
setTimeout(() => {
console.log(this.name); // jack
}, 100);
let b = obj.verdict;
// this指向obj
obj.verdict(); // false
// this指向window
b(); // true
setTimeout(() => {
console.log(this === window); // true
}, 100);
二、箭头函数
- 箭头函数
没有自己的this,是继承而来的- 箭头函数的this指向它外层
包裹它的最近的非箭头函数的this- 箭头函数使用
bind、apply和call重新绑定this的时候,会自动忽略掉第一个参数,即重新绑定的this对箭头函数是没有影响的
// 浏览器环境
// 在全局作用域中自调用的箭头函数,this指向window
(() => console.log(this === window))(); // true
let obj = {
foo() {
console.log(this === obj); // true
// 箭头函数的this指向它外层包裹它的最近的非箭头函数的this
// 因为外层最近的非箭头函数是 foo 而foo的this指向obj
return () => {
console.log(this === obj); // true
};
},
};
obj.foo()();
三、bind,call和apply重新指定后的函数,
- 若第一个参数为对象,指向第一个参数
- 若第一个参数为空,就和普通函数一样
// 浏览器环境
let obj = {
name: 'tom',
foo() {
console.log(this.name);
},
};
let obj2 = {
name: 'jack',
};
let name = 'bob';
// 谁调用的指向谁
obj.foo(); // tom
// 使用call、apply和bind后,this指向指向第一个参数
obj.foo.call(obj2); // jack
obj.foo.apply(obj2); // jack
obj.foo.bind(obj2)(); // jack
obj.foo.call(); // tom
obj.foo.apply(); // tom
obj.foo.bind()(); // tom