隐式绑定与隐式丢失

  • 隐式绑定

另外一条需要考虑的规则是调用位置是否有上下文对象,或者说是否被某个对象拥有或者包含,不过这种说法可能会造成一些误导。

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元素上。

Last updated