先簡單說兩句
相信很多朋友在剛學習Javascript
都被Javascript
的this
弄得很混亂,由於我一開始就是學習Java
先的,很自然就Java
中的this
代入了Javascript
中,其實這是一個重大的錯誤,有人(我)說「如果上帝用七天打造這個世界,那麼Javascript
就是在最後0.01秒才匆匆設計的」,現在就讓我跟大家詳細說說Javascript
的this
吧!
this的意義
在Java
中,this
是一個引用對象,引用的就是這個對象自身,在Javascript
中也會有這種場景,如以下代碼的this
便指向new
出來的那個對象自身
1 | export class People{ |
又或者在使用Javascript
的對象時,this
也是指向car
對象本身,但這種情況上面跟通過new
關鍵字又有一些不一樣。
1 | const car = { |
在我現在的工作中,經過需要使用到React
,一般在React
的constructor
中需要做以下這件事,就是需要bind
綁定,為甚麼需要呢,不綁定會怎樣?
1 | export class Input extends React.Component{ |
還有一種更簡單的情況,在瀏覽器打開chrome devTools,在console面版中輸入this
,看看會出現甚麼東西。為甚麼會輸出window呢?
接著我跟大家解釋釋,究竟this的意義是甚麼,其實this
是指運行期間的上下文,根據不同的情況有不同的綁定規則。
this的綁定規則
默認綁定
默認綁定就是最簡單的情況,在全域或者不在函數內部使this
的時候,this
指向的便全局變量,在瀏覽器中是window
,在nodejs
中便是global
,默認綁定會在嚴格下失效,即嚴格模式,默認綁定的this
會指向undefined
。上面第四個例子便是默認綁定。
隱式綁定
當函數被調用時,若函數引用具有上下文對象,則隱式綁定會將 this 綁定到這個上下文對象。第二個例子說的就是隱式綁定,在this
的綁定規則裡,最容易出錯的就是隱式綁定,來看一段代碼,最後的那兩個函數會分別返回a
和surprise
,這種情況叫做隱式丟失,丟失的就是this
,bar
是obj.foo
的一個函數別名,在調用bar
的時候會丟失對obj
的this
引用,而直接是綁定到全局的對象中。
1 | // 非嚴格模式 |
顯式綁定
顯式綁定就要為了避免隱式丟失的出現,通過apply
、call
和bind
三個方法來顯式的綁定要調用函數內部的this
,看看例子最直接,在例子就直接指定this
的值,這樣可以避免出現丟失的問題,所以現在為甚麼第三個例子中React constructor
需要用bind
綁定一下。
1 | const obj1 = { |
new綁定
第一個例子中,我們通過一個new
關鍵字「實例化」了一個對象,實際上的new
過程只做了下面幾件事:
- 創建一個新的對象
- 將新的對象的
__prototype__
屬性指向函數的prototype
- 將函數的
this
綁定向新的對象 - 調用函數
注意第三步,這裡就是實際上new
綁定出現的原因,因為在new
關鍵字的執行過程已經把新創建的對象綁定到函數的this
裡,所以在new
出來的對象裡面的this在運行時是會指向這個對象的。
優先級
依次為new綁定
、顯式綁定
、隱式綁定
、默認綁定
。
Javascript
中的this
機制其實還有一層,就是this
在prototype
原型鏈上的查找,可以理解this
是一個二維平面,水平方向是綁定規則,垂直方向就是prototype
原型鏈和JS的各種作用域。
下期將為大家介紹Javascript
的原型鏈和作用域。
本人獻醜了,大家加油~!