this的四种绑定规则:默认绑定、隐式绑定、显式绑定和new绑定,分别对应函数的四种调用方式:独立调用、方法调用、间接调用和构造函数调用。
1、默认绑定
- 全局环境中,this默认绑定到window
console.log(this === window);//true
- 函数独立调用时,this默认绑定到window
function foo(){
console.log(this === window);
}
foo(); //true
- 被嵌套的函数独立调用时,this默认绑定到window
//虽然test()函数被嵌套在obj.foo()函数中,但test()函数是独立调用,而不是方法调用。所以this默认绑定到window
var a = 0;
var obj = {
a : 2,
foo:function(){
function test(){
console.log(this.a);
}
test();
}
}
obj.foo();//0
如果调用obj.foo()本身,foo()函数中的this指向调用函数的对象,即obj对象
var a = 0;
var obj = {
a: 2,
foo: function () {
console.log(this.a);
}
}
obj.foo();//2
- IIFE立即执行函数实际上是函数声明后直接调用执行
var a = 0;
function foo(){
(function test(){
console.log(this.a); //this指向window
})()
};
var obj = {
a : 2,
foo:foo
}
obj.foo();//0
- 闭包中内部函数的this默认指向window对象
var a = 0;
function foo(){
function test(){
console.log(this.a);
}
return test;
};
var obj = {
a : 2,
foo:foo
}
obj.foo()();//0
由于闭包的this默认绑定到window对象,但又常常需要访问嵌套函数的this,所以常常在嵌套函数中使用var that = this,然后在闭包中使用that替代this,使用作用域查找的方法来找到嵌套函数的this值
2、隐式绑定
当函数作为对象里的方法被调用时, this
是调用该函数的对象。
function foo(){
console.log(this.a);
};
var obj1 = {
a:1,
foo:foo,
obj2:{
a:2,
foo:foo
}
}
//foo()函数的直接对象是obj1,this隐式绑定到obj1
obj1.foo();//1
//foo()函数的直接对象是obj2,this隐式绑定到obj2
obj1.obj2.foo();//2
隐式丢失
隐式丢失是指被隐式绑定的函数丢失绑定对象,从而默认绑定到window。这种情况容易出错却又常见
var a = 0;
function foo(){
console.log(this.a);
};
var obj = {
a : 2,
foo:foo
}
//把obj.foo赋予别名bar,造成了隐式丢失,因为只是把foo()函数赋给了bar,而bar与obj对象则毫无关系
var bar = obj.foo;
bar();//0
3、显示绑定
通过call()、apply()、bind()方法把对象绑定到this上,叫做显式绑定。对于被调用的函数来说,叫做间接调用
var a = 0;
function foo(){
console.log(this.a);
}
var obj1 = {
a:1
};
var obj2 = {
a:2
};
foo.call(obj1);//1
foo.call(obj2);//2
【API】
javascript中新增了许多内置函数,具有显式绑定的功能,如数组的5个迭代方法:map()、forEach()、filter()、some()、every()
var id = 'window';
function foo(el){
console.log(el,this.id);
}
var obj = {
id: 'fn'
};
[1,2,3].forEach(foo);//1 "window" 2 "window" 3 "window"
[1,2,3].forEach(foo,obj);//1 "fn" 2 "fn" 3 "fn"
4、new绑定
如果函数或者方法调用之前带有关键字new,它就构成构造函数调用。对于this绑定来说,称为new绑定。理解new一个对象发生的过程。this指向创建的新对象。
function fn(){
this.a = 2;
}
var test = new fn();
console.log(test.a);//2