另外一条需要考虑的规则是调用位置是否有上下文对象,或者说是否被某个对象拥有或者包含,不过这种说法可能会造成一些误导。
function foo(){
console.log( this.a );
}
var obj = {
a : 2,
foo : foo
}
obj.foo(); //2
需要注意的是,无论直接在obj中定义,还是先定义再添加为引用属性,这个函数严格来说都不属于obj对象。
然而,调用位置会使用obj上下文来引用函数,因此你可以说函数被调用时obj对象"拥有"或者"包含"函数引用。
对象属性引用链中只有上一层或者说最后一层在调用位置中起作用。
function foo(){
console.log( this.a );
}
var obj2 = {
a : 42,
foo : foo
};
var obj1 = {
a : 2,
obj2:obj2
};
obj1.obj2.foo();//42
隐式丢失
一个常见的this绑定问题就是被隐式绑定的函数会丢失绑定对象,也就是说它会应用默认绑定,从而将this绑定到全局对象或者undefined上,取决于是否是严格模式。
function foo(){
console.log( this.a );
}
var obj = {
a : 2,
foo : foo
};
var bar = obj.foo; //函数别名
var a = 'global';
bar();//'global'
虽然bar是obj.foo
的一个引用,但是实际上,它引用的是foo函数本身,因此此时的bar()
其实是一个不带任何修饰的函数调用,因此应用了默认绑定。
function foo(){
console.log( this.a );
}
function doFoo(fn){
// fn 其实引用的是foo
fn();
}
var obj = {
a : 2,
foo : foo
};
var a = "global";
doFoo( obj.foo );//'global'
参数传递其实就是一种隐式赋值,因此我们传入函数时也会被隐式赋值,所以结果和上一个例子一样。
如果把函数传入语言内置函数而不是传入自己定义的函数,结果是一样的,没有区别。
function foo(){
console.log(this.a);
}
var obj = {
a:2,
foo:foo
};
var a = "global" //a是全局对象的属性
setTimeout( obj.foo ,100);//'global'
JavaScript 环境中内置的setTimeout()
函数实现和下面的伪代码类似:
function setTimeout(fn,delay){
//等待delay毫秒
fn(); // <--调用位置
}
回调函数丢失 this 绑定是非常常见的。除此之外,调用回调函数的函数可能会修改this,在一些流行的JavaScript库中处理器常会把回调函数的this强制绑定到触发事件的DOM元素上。