JavaScript 中的 this 依赖于函数的调用方式。所以,想要明白this 的指向问题,还必须先研究函数在JavaScript中是如何被调用的。
1. 作为普通函数调用
非严格模式下指向window对象,严格模式下为undefined。
function func1() {
console.log(this === window); // true
}
func1();
const func2 = function () {
console.log(this === window); // true
}
func2();
// 严格模式
function func3() {
"use strict";
console.log(this); // undefined
}
func3();
2. 作为对象方法调用
如果一个函数作为一个对象的方法来调用时,this 指向这个对象。
const obj = {
name: 'doudou',
func: function() {
console.log(this === obj); // true
console.log(this.name); // 'doudou'
}
};
obj.func();
有些情况下,会丢失绑定对象,指向全局对象
var obj = {
a: 2,
foo: foo
};
var bar = obj.foo; // 函数别名
var a = "oops, global"; // a是全局对象的属性
bar(); // "oops, global"
var name = "The window";
var object = {
name: 'My Object',
getNameFunc: function () {
console.log(this); // window
return function () {
return this.name;
}
}
}
console.log(object.getNameFunc()()); // "The window";
匿名函数的 this 永远指向 window
3. 作为构造函数调用
使用new来调用函数时,this指向创建的新对象。
function Foo(a) {
this.a = a;
}
var bar = new Foo(2); // bar和Foo(..)调用中的this进行绑定
console.log( bar.a ); // 2
4. 使用apply、call和bind方法进行调用
这三个方法用于指定函数调用时 this 指向的对象。
- apply() 方法接收两个参数:一个是 this 绑定的对象,一个是参数数组。其中第二个参数可以是 Array 的实例,也可以是 arguments 对象。
- call() 方法和 apply() 方法的作用相同,它们的区别仅在于接收参数的方式不同。对于 call() 方法而言,第一个参数是 this 值没有变化,变化的其余参数都直接传递给函数。换句话说,在使用 call() 方法时,传递给函数的参数 必须逐个列举出来。
- bind方法通过传入一个对象,返回一个this绑定了新对象的
function foo() {
console.log( this.a );
}
const obj = {
a: 2
};
foo.call(obj); // 2 调用foo时强制把foo的this绑定到obj上
foo.apply(obj); // 2
const newFunc = foo.bind(obj);
newFunc() // 2
PS:这四种方式,使用构造器调用模式的优先级最高,然后是 apply 、call和bind调用模式,然后是方法调用模式,然后是普通函数调用模式。
5. 箭头函数中的this
不会使用上文的四条标准的绑定规则, 而是根据当前的词法作用域来决定this, 具体来说,箭头函数会继承外层函数,调用的 this 绑定( 无论 this 绑定到什么),没有外层函数,则是绑定到全局对象(浏览器中是window)。 这其实和 ES6 之前代码中的 self = this 机制一样。
function foo() {
// 返回一个箭头函数
return (a) => {
// this继承自foo()
console.log( this.a );
};
}
var obj1 = {
a: 2
};
var obj2 = {
a: 3
}
var bar = foo.call( obj1 );
bar.call( obj2 ); // 2,不是3!
解析:
foo()内部创建的箭头函数会捕获调用时foo()的this。
由于foo()的this绑定到obj1,bar(引用箭头函数)的this也会绑定到obj1,箭头函数的绑定无法被修改(new也不行)
题目一:
var num = 1;
var myObject = {
num: 2,
add: function() {
this.num = 3;
(function() {
console.log(this.num); // 这里的this指向window
this.num = 4;
})();
console.log(this.num); // 这里的this指向myObject
},
sub: function() {
console.log(this.num) // 这里的this指向myObject
}
}
myObject.add(); // 1 3
console.log(myObject.num); // 3
console.log(num); // 4
var sub = myObject.sub;
sub(); //4