JavaScript中this關(guān)鍵字(下)

上一篇文章中講了下this的作用和部分綁定規(guī)則JavaScript中this關(guān)鍵字(上) - 簡書,這篇文章將上篇中剩下的部分說完。

this綁定規(guī)則:

3 .顯示綁定:

在靜態(tài)綁定中可以看到,必須在一個對象內(nèi)部包含一個指向函數(shù)的屬性,并通過這個屬性間接的去引用函數(shù),從而把this隱式的綁定到這個對象上。

如果不想在對象內(nèi)部包含函數(shù)的引用,而想在某個對象上強制調(diào)用函數(shù),這就是顯示綁定,怎么做才能做到顯示綁定呢?js中所有的函數(shù)都有一些公有的方法,比如call(),apply(),bind()這三種方法。那這三種方法該怎么用?首先,這三個方法的第一個參數(shù)都可以接受一個對象,它們會把對象綁定到this上,接著在調(diào)用函數(shù)時指定this,這種方法稱為顯示綁定。這三者的區(qū)別是:call()的第二個參數(shù)開始接受的是單獨的參數(shù),例如:xxx.call(obj,argument1,argument2);apply()的第二個參數(shù)開始則接受一個參數(shù)數(shù)組,例如:xxx.apply(obj,[args1,args2]);bind的第二個參數(shù)以及以后的參數(shù)加上綁定函數(shù)運行時本身的參數(shù)按照順序作為原函數(shù)的參數(shù)來調(diào)用原函數(shù)。

4.new綁定

用new的話一般是用于初始化構(gòu)造函數(shù)(類)的時候用的多一些,比如我最近在寫svg的時候就用到構(gòu)造函數(shù)(類)。使用方法如下:

實例1
實例2

在實例1中可以看到有一個svg的類,使用的時候用new就可以了。

new做了什么樣的操作呢?

1. 創(chuàng)建(或者說構(gòu)造)一個全新的對象。

2. 這個新對象會被執(zhí)行 [[ 原型 ]] 連接。

3. 這個新對象會綁定到函數(shù)調(diào)用的 this 。

4. 如果函數(shù)沒有返回其他對象,那么 new 表達式中的函數(shù)調(diào)用會自動返回這個新對象。

如上面兩張圖,在使用new來調(diào)用Svg(...)時,會構(gòu)造一個新對象并把它綁定到Svg()調(diào)用中的this上。

現(xiàn)在我們已經(jīng)大概了解了函數(shù)中調(diào)用this綁定的四條規(guī)則,我們需要做的就是找到函數(shù)的調(diào)用位置并判斷使用了那條規(guī)則。但如果某個調(diào)用位置可以應(yīng)用多條規(guī)則該怎么辦?接下來我們將探索一下綁定規(guī)則的優(yōu)先級。

毫無疑問,默認(rèn)綁定的優(yōu)先級是四條規(guī)則中最低的,我們先不考慮它

隱式綁定和顯示綁定哪個優(yōu)先級更高?上代碼


實例3

可以看到,顯示綁定的優(yōu)先級更高,也就是說在判斷時應(yīng)當(dāng)先考慮是否優(yōu)先應(yīng)用顯示綁定

那隱式綁定和new綁定哪個高呢?


實例4

可以看到new綁定要比隱式綁定優(yōu)先級高,那new綁定和顯示綁定誰的優(yōu)先級更高呢?

先回憶一下bind()是如何工作的,bind()會創(chuàng)建一個新的包裝函數(shù),這個函數(shù)會忽略它當(dāng)前的this綁定(無論綁定的對象是什么),并把提供的對象綁定到this上。這樣看起來要比new綁定的優(yōu)先級更高,無法使用new來控制this的綁定。


實例5

從實例5中可以看到,bar被綁定到了obj1上,但new bar(3)并沒有像預(yù)計的那樣把obj1.a修改為3,相反,new修改了硬綁定調(diào)用bar()的this,因為使用new的來進行綁定,會得到一個名字為baz的新對象,并且baz.a的值是3。

所以綁定規(guī)則的優(yōu)先級是:

new綁定 > 顯示綁定 >隱式綁定 >默認(rèn)綁定

不過規(guī)則總有例外,在某些特定的場景中this的綁定行為會出乎意料。

1.忽略this

不知道大家有沒有遇到過這種情況:

function foo() {

console.log( this.a );

}

var a = 2;

foo.call( null ); // 2

如果把undefined或者null傳入到call,apply或者bind中,這些值在調(diào)用時會被忽略,this會使用到默認(rèn)規(guī)則。

什么情況下會傳入null呢?

一種常見的做法就是使用apply來"展開"一個數(shù)組,并當(dāng)做參數(shù)傳入一個函數(shù)

function foo(a,b) {

console.log( "a:" + a + ", b:" + b );

}

foo.apply( null, [2, 3] ); // a:2, b:3

如果函數(shù)并不關(guān)心this的話,仍然需要傳入一個站位值,比如null.

但是,如果函數(shù)確實使用了this,那默認(rèn)綁定規(guī)則會把this綁定到全局對象(window)

2.間接引用

比如在賦值時發(fā)生的間接引用:

function foo() {

console.log(this.a);

}

vara=2;

varo={a:3,foo:foo};

varp={a:4};

o.foo();// 3

(p.foo=o.foo)();// 2

p.foo=o.foo的返回值是目標(biāo)函數(shù)的引用,因此調(diào)用位置是foo()而不是p.foo()或者o.foo(),間接引用時,this也會采取默認(rèn)綁定的規(guī)則。

3.箭頭函數(shù)

es6中提供了一個特殊函數(shù)類型:箭頭函數(shù),它不適用于上面介紹的四種規(guī)則,實際上它是根據(jù)外層(函數(shù)或者全局)的作用域來決定this的。

function foo() {

// 返回一個箭頭函數(shù)

return (a) => {

//this 繼承自 foo()

console.log( this.a );

};

}

var obj1 = {

a:2

};

var obj2 = {

a:3

};

var bar = foo.call( obj1 );

bar.call( obj2 ); // 2, 不是 3 !

箭頭函數(shù)最常用的地方在于回調(diào)函數(shù)中,例如事件處理或者定時器中。

總結(jié):

要判斷一個函數(shù)中的this指向,就需要找到這個函數(shù)的直接調(diào)用位置,找到后可以根據(jù)規(guī)則來判斷this的綁定對象

1.new調(diào)用會綁定到新創(chuàng)建的對象

2.call或者apply或者bind則綁定到指定的對象

3.上下文調(diào)用則綁定到對應(yīng)的上下文對象

4.默認(rèn)規(guī)則:嚴(yán)格模式下綁定到undefined,否則綁定到全局對象

箭頭函數(shù)并不會使用到以上四種規(guī)則,而是根據(jù)當(dāng)前的詞法作用域來決定this,也就是說,箭頭函數(shù)會繼承外層函數(shù)調(diào)用的this綁定。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,554評論 19 139
  • 官方中文版原文鏈接 感謝社區(qū)中各位的大力支持,譯者再次奉上一點點福利:阿里云產(chǎn)品券,享受所有官網(wǎng)優(yōu)惠,并抽取幸運大...
    HetfieldJoe閱讀 7,004評論 15 54
  • 特別說明,為便于查閱,文章轉(zhuǎn)自https://github.com/getify/You-Dont-Know-JS...
    殺破狼real閱讀 816評論 0 1
  • 1. this之謎 在JavaScript中,this是當(dāng)前執(zhí)行函數(shù)的上下文。因為JavaScript有4種不同的...
    百里少龍閱讀 1,093評論 0 3
  • 1.函數(shù)調(diào)用棧和調(diào)用位置 在函數(shù)執(zhí)行的時候,會有一個活動記錄(也叫執(zhí)行上下文)來記錄函數(shù)的調(diào)用順序,這個就是函數(shù)調(diào)...
    lightNate閱讀 606評論 1 14

友情鏈接更多精彩內(nèi)容