關於this的全面解析(下)

關於this的全棉解析(上)的文章地址segmentfault

判斷this

  1. 函數是否在new中調用(new綁定)?若是是的話this綁定的是新建立的對象。瀏覽器

  2. bar = new foo()安全

  3. 函數是否經過call、apply(顯式綁定)或者硬綁定調用?若是是的話,this綁定的是指定的對象。app

  4. bar = foo.call(obj2)函數

  5. 函數是否在某個上下文對象中調用(隱式綁定)?若是是的話,this綁定的是那個上下文對象。this

  6. bar = obj1.foo()prototype

  7. 若是都不是的話,使用默認綁定。若是在嚴格模式下,就綁定到undefined,不然綁定到全局對象。code

  8. bar = foo();對象

綁定例外

被忽略的this

若是把null或者undefined做爲this的綁定對象傳入call、apply或者bind,這些值在調用時會被忽略,實際應用的是默認綁定規則。ip

function foo() {
    console.log(this.a);
    }
    var a = 2;
    foo.call(null); //2

然而,老是使用null來忽略this綁定可能產生一些反作用。若是某個函數確實使用了this,那默認綁定規則會把this綁定到全局對象(在瀏覽器中全局對象爲window),這將致使不可預計的後果(好比修改全局對象)。
顯而易見,這種方式可能會致使許多難以分析和追蹤的bug。

更安全的this

一種「更安全」的作法是傳入一個特殊的對象、把this綁定到這個對象不會對你的程序產生反作用。
在JavaScript中建立一個空對象最簡單的方法都是Object.create(null),可是並不會建立Object.prototype這個委託。

function foo(a, b) {
        console.log("a:" + a + ", b:" + b);
    }
    //建立一個新對象
    var emptyObj = Object.create(null);
    foo.apply(emptyObj, [2, 3])
    var bar = foo.bind(emptyObj, 2);
    bar(3);
間接引用

間接引用最容易在賦值時發生。

function foo() {
        console.log(this.a);
    }
    var a = 2;
    var o = {
        a: 3,
        foo: foo
    };
    var p = {
        a: 4
    };
    o.foo(); //3
    (p.foo = o.foo)() //2

賦值表達式p.foo= o.foo的返回值是目標函數的引用,所以調用位置是foo()而不是p.foo()或者o.foo(),因此綁定的是全局對象。

小結

若是要判斷一個運行中函數的this綁定,就須要找到這個函數的直接調用位置。找到以後就能夠順序應用下面這四條規則來判斷this的綁定對象。

  1. 由new調用?綁定到新建立的對象。

  2. 由call或者apply(或者bind)調用?綁定到指定的對象。

  3. 由上下文對象調用?綁定到那個上下文對象。

  4. 默認:在嚴格模式下綁定到undefined,不然綁定到全局對象。

相關文章
相關標籤/搜索