Javascript解析this機制

理解this機制的第一步首先是要明白 this既不指向函數(shù)自身也不指向函數(shù)的詞法作用域,this實際上是在函數(shù)被調用時發(fā)生綁定的,所以要先了解調用棧和函數(shù)的調用位置。

調用棧就是為了達到當前執(zhí)行位置而調用的所有函數(shù),而調用位置就在當前執(zhí)行函數(shù)的前一個調用中。而調用位置決定了this的綁定。

function fn1(){

//當前調用棧是:fn1

//當前調用位置是全局作用域

console.log("fn1");

fn2();//fn2的調用位置

}

function fn2(){

//當前調用棧是: fn1 => fn2

//當前調用位置在 fn1中

console.log("fn2");

}

fn1() //fn1的調用位置

那么調用位置是如何決定this的綁定的呢?

在調用位置中,this綁定由以下四條規(guī)則來判定綁定對象:

1、默認綁定

如果函數(shù)是直接使用不帶任何修身的函數(shù)引用進行調用的,只能使用默認規(guī)則,無法應用其他規(guī)則,在下面例子中,this是默認綁定到全局對象,如果是在嚴格模式下,this就會默認綁定到undefined.

function fn1(){

console.log(this.a);

}

var a = 1;

fn1() // 2

2、隱式綁定

如果調用位置有上下文對象,就會應用隱式綁定規(guī)則,this就會被綁定到上下文對象上。

function fn(){

console.log(this.a);

}

var obj = {

a: 2,

fn: fn

};

obj.fn() // 2

當fn()被調用時候,它是指向obj對象的,隱式規(guī)則會把函數(shù)調用中的this綁定到這個上下文對象上。

隱式丟失

但是有時候被隱式綁定的函數(shù)會丟失綁定對象。

接上述代碼

var fnn() = obj.foo;

var a = 3;

fnn();//3

雖然fnn是obj.foo的一個引用,但其實它調用的是fn()函數(shù)本身,且不帶任何修飾,自動應用默認綁定規(guī)則,將this綁定到了全局對象中。這個隱式丟失問題有沒有解決辦法呢,請繼續(xù)往下看。

3、顯式綁定

有隱式綁定就會有顯式綁定,就像有光就有暗一樣,當我們不想在一個對象里引用函數(shù),而是直接強制調用函數(shù)時該怎么做呢?這里我們就是用js一些特殊函數(shù)來達成這樣的效果。例如apply()和call(),它們的第一個參數(shù)都是一個對象,它們會把this綁定到這個對象,接著在函數(shù)調用時指向這個this。

可是顯式綁定還是無法解決隱式丟失的問題,但是它的一個變種——硬綁定,可以解決這個問題。

function fn(){

console.log(this.a);

}

var obj = {

a: 2,

};

var fnn() = function(){

fn.call(obj)

};

fnn();//2

fnn.call(window) // 2 硬綁定的函數(shù)不能再改變它的this綁定。

由于硬綁定比較常用,ES5提供了內(nèi)置的方法:Function.prototype.bind,還有一種實現(xiàn)方式是

許多第三方庫以及許多內(nèi)置的API的“上下文”,即內(nèi)置函數(shù)的一些可選參數(shù)。

function fn(e){

console.log(e,this.a);

}

var obj = {

a: "mama"

};

[1,2,3].forEach(fn,obj) // 1 mama 2 mama 3 mama

實際上它們也是通過apply()和call()來實現(xiàn)顯式綁定的。

4、new綁定

這是第四條也是最后一條綁定規(guī)則,new綁定。

js所有的函數(shù)包括內(nèi)置函數(shù)都可以用new調用,被稱為構造函數(shù)調用,其實js并不存在所謂的“構造函數(shù)”,只有對于函數(shù)的“構造調用”

發(fā)生構造調用,即用new來調用時,會自動執(zhí)行以下操作:

1、創(chuàng)建一個全新的對象

2、這個新對象會被執(zhí)行原型連接

3、這個新對象會被綁定到函數(shù)調用的this上

4、如果函數(shù)沒有返回其他對象,那么會自動返回這個新的對象

判斷this綁定

現(xiàn)在我們可以根據(jù)優(yōu)先級來判斷函數(shù)在調用位置應用的是哪個規(guī)則:

1、如果函數(shù)是在new中調用,this綁定的是新創(chuàng)建的對象

2、如果函數(shù)通過apply()、call()或硬綁定,this綁定的是指定的對象

3、如果函數(shù)是在某個上下文對象中調用,this綁定的是這個上下文對象

4、如果都不是則使用默認綁定,非嚴格模式下this綁定全局對象,嚴格模式下綁定undefined

被忽略的this

如果你把null或者undefined作為this 的綁定對象傳入call()、apply()或bind()中,這些值在調用時會被忽略,實際使用的還是默認綁定規(guī)則。

ES6箭頭函數(shù)

之前介紹的四條規(guī)則可以應用所以的正常函數(shù),但是ES6的箭頭函數(shù)是一種無法使用這些規(guī)則的特殊函數(shù)類型。它并不是function關鍵字定義的,并不使用這四條規(guī)則,而是由外層作用域來決定this。

實際上在ES6之前我們就已經(jīng)在使用一種幾乎和箭頭函數(shù)完全一樣的模式,就是使用 self = this。從本質上來說,它們都是想要替代this機制。

this綁定的水還很深,這里只是介紹了一些粗淺的綁定規(guī)則知識,更深入的部分我也還沒學會! :)

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

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

  • 工廠模式類似于現(xiàn)實生活中的工廠可以產(chǎn)生大量相似的商品,去做同樣的事情,實現(xiàn)同樣的效果;這時候需要使用工廠模式。簡單...
    舟漁行舟閱讀 8,118評論 2 17
  • 單例模式 適用場景:可能會在場景中使用到對象,但只有一個實例,加載時并不主動創(chuàng)建,需要時才創(chuàng)建 最常見的單例模式,...
    Obeing閱讀 2,314評論 1 10
  • 官方中文版原文鏈接 感謝社區(qū)中各位的大力支持,譯者再次奉上一點點福利:阿里云產(chǎn)品券,享受所有官網(wǎng)優(yōu)惠,并抽取幸運大...
    HetfieldJoe閱讀 7,002評論 15 54
  • 一、今日學習 1.為完成教師節(jié)小報,學習思維導圖武林計劃的作業(yè),邊學邊畫小報作業(yè),1.5小時。 二、訓練的項目和成...
    世話實說閱讀 243評論 0 0
  • 你發(fā)出去了,耶,不過一天的學習收獲不少。
    花花花花美閱讀 190評論 0 0

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