關於this的全棉解析(上)的文章地址segmentfault
函數是否在new中調用(new綁定)?若是是的話this綁定的是新建立的對象。瀏覽器
bar = new foo()安全
函數是否經過call、apply(顯式綁定)或者硬綁定調用?若是是的話,this綁定的是指定的對象。app
bar = foo.call(obj2)函數
函數是否在某個上下文對象中調用(隱式綁定)?若是是的話,this綁定的是那個上下文對象。this
bar = obj1.foo()prototype
若是都不是的話,使用默認綁定。若是在嚴格模式下,就綁定到undefined,不然綁定到全局對象。code
bar = foo();對象
若是把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綁定到這個對象不會對你的程序產生反作用。
在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的綁定對象。
由new調用?綁定到新建立的對象。
由call或者apply(或者bind)調用?綁定到指定的對象。
由上下文對象調用?綁定到那個上下文對象。
默認:在嚴格模式下綁定到undefined,不然綁定到全局對象。