注意:
this
是在函数被调用的时候发生的绑定,它指向什么完全取决于在哪里被调用。
在严格和非严格模式下,this
的指向有所不同
function f1() {
return this;
}
// In a browser:
f1() === window; // true
// In Node:
f1() === global; // true
//严格模式如下:
function f2() {
'use strict'; // see strict mode
return this;
}
f2() === undefined; // true
那么在函数在执行过程中调用位置如何决定this的绑定对象?
有四条规则
默认绑定
就是,常用的函数调用。
如上f1、f2
函数的调用,都采用【默认绑定】。绑定到全局对象window
或者global
上。
隐式绑定
就是,对象的方法调用。如果说函数的调用位置有上下文对象,或者说被某个对象拥有或者包
含,那就是隐式绑定。
function foo() {
console.log( this.a );//this指向obj对象
}
var obj = {
a: 2,
foo: foo
};
obj.foo(); // 2
var obj1 =
当含有this
的方法赋值给变量,然后被调用时,会发生隐式丢失,即丢失了绑定的对象。
例如:
function foo() {
console.log(this.a);
}
var obj = {
a: 2,
foo: foo
};
var bar = obj.foo; // 函数别名!
var a = "oops, global"; // a 是全局对象的属性
bar(); // "oops, global"
foo
函数隐式绑定了obj
对象,在赋值给变量bar
后,被调用打印this.a
结果是全局变量a
的值。
隐式绑定丢失所绑定的对象后,采用默认的绑定方式,this
执行全局环境
当含有this
的方法应用于回调函数时,也会发生隐式丢失。
没错,这种情况同样也发生在回调函数,类比“赋值给变量”。
function foo() {
console.log(this.a);
}
var obj = {
a: 2,
foo: foo
};
var a = "oops, global"; // a 是全局对象的属性
setTimeout( obj.foo, 100 );//oops,global
那么,上述遇到的隐式丢失该如何解决呢?这就需要说到下一个规则【显示绑定】
显示绑定
可以在某个对象上强制调用函数。或者说改变this的指向
不得不说call
、apply
、bind
三个函数
这三个方法可以解决如上【隐式丢失】的问题。
new绑定
执行var o = new Foo();
,new到底发生了什么?
var o = new Object();
o.[[Prototype]] = Foo.prototype;
Foo.call(o);
使用new
来调用函数,或者说发生构造函数调用,则会自执行如下操作:
- 创建一个全新的对象
- 这个新对象会被执行
[[原型]]
连接 - 这个新对象会绑定到函数调用的
this
上 - 如果函数没有返回其他对象,则会默认返回
this
,也就是这个新对象。
注意,第4点。默认返回this
,也就是说可以返回其他对象。比如:
function Man(name) {
console.log('man', this);
this.name = name;
return {}; //函数有自己的返回对象
}
function Woman(name) {
console.log('woman:', this);
this.name = name;
}
var man = new Man('Davin');
console.log(man) // {}
var woman = new Woman('Lisa');
console.log(woman) //{name: "Lisa"}
箭头函数
在箭头函数中,this
与封闭词法环境的this
保持一致。在全局代码中,它将被设置为全局对象。
var globalObject = this;
var foo = (() => this);
console.log(foo() === globalObject); // true
无论如何,foo
的 this
被设置为他被创建时的环境(在上面的例子中,就是全局对象)。这同样适用于在其他函数内创建的箭头函数:这些箭头函数的this
被设置为封闭的词法环境
的。如下:
// 作为对象的一个方法调用
var obj = {foo: foo};
console.log(obj.foo() === globalObject); // true
// 尝试使用call来设定this
console.log(foo.call(obj) === globalObject); // true
// 尝试使用bind来设定this
foo = foo.bind(obj);
console.log(foo() === globalObject); // true
箭头函数中this的指向并未发生变化。
参考阅读
《你不知道的JavaScript(上)》
MDN 之 this
透彻理解并掌握JavaScript的this