前文已闡述JavaScript this
關鍵字的基礎用法。 this
指向的關鍵在於運行時上下文。然而,上下文在預期之外發生變化時,問題就出現了。本文將重點介紹這種情況,以及如何解決。
核心要點
this
關鍵字指向當前執行上下文,理解它對於操作和交互對象至關重要,尤其是在面向對象編程或使用大量依賴this
的框架和庫時。 this
關鍵字的常見問題包括在提取的方法、回調函數和閉包中使用。這些問題可以通過使用bind()
方法將this
關鍵字顯式綁定到正確的對象來解決。 this
值。箭頭函數的詞法綁定無法被覆蓋,使其成為維護this
正確上下文更優雅的解決方案。 this
的值取決於函數的調用方式。在方法中,this
指向它所屬的對象;在普通函數中,this
指向全局對象;如果用new
關鍵字(作為構造函數)調用函數,this
指向新創建的對象;在事件處理程序中,this
指向接收事件的元素;最後,可以使用call()
、apply()
或bind()
顯式設置this
。 解決常見問題
本節將探討使用this
關鍵字時出現的一些最常見問題,並學習如何解決它們。
1. 在提取的方法中使用this
最常見的錯誤之一是嘗試將對象的方法賦值給變量,並期望this
仍然指向原始對象。如下例所示,這行不通。
var car = { brand: "Nissan", getBrand: function() { console.log(this.brand); } }; var getCarBrand = car.getBrand; getCarBrand(); // 输出:undefined
即使getCarBrand
似乎是car.getBrand()
的引用,實際上它只是getBrand()
自身的另一個引用。我們已經知道,調用位置決定上下文,此處調用位置是getCarBrand()
,這是一個簡單的函數調用。為了證明getCarBrand
指向一個無基礎的函數(未綁定到任何特定對象的函數),只需在代碼底部添加alert(getCarBrand);
,您將看到以下輸出:
var car = { brand: "Nissan", getBrand: function() { console.log(this.brand); } }; var getCarBrand = car.getBrand; getCarBrand(); // 输出:undefined
getCarBrand
只包含一個普通函數,它不再是car
對象的成員方法。因此,在這種情況下,this.brand
實際上轉換為window.brand
,當然它是未定義的。如果我們從對像中提取方法,它又變成了一個普通函數。它與對象的連接被切斷,不再按預期工作。換句話說,提取的函數沒有綁定到它所取自的對象。那麼我們如何補救呢?如果我們想保留對原始對象的引用,我們需要在將getBrand()
函數賦值給getCarBrand
變量時,顯式地將getBrand()
函數綁定到car
對象。我們可以使用bind()
方法來實現。
function(){ console.log(this.brand); }
現在,我們得到了正確的輸出,因為我們成功地將上下文重新定義為我們想要的樣子。
2. 在回調函數中使用this
下一個問題發生在我們傳遞一個方法(使用this
作為參數)作為回調函數時。例如:
var getCarBrand = car.getBrand.bind(car); getCarBrand(); // 输出:Nissan
即使我們使用car.getBrand
,我們實際上只得到附加到按鈕對象的函數getBrand()
。將參數傳遞給函數是隱式賦值,因此這裡發生的情況與上一個示例幾乎相同。不同之處在於,現在car.getBrand
不是顯式賦值,而是隱式賦值。結果幾乎相同——我們得到的是一個普通函數,綁定到按鈕對象。換句話說,當我們在一個對像上執行一個方法時,該對象與最初定義該方法的對像不同,this
關鍵字不再指向原始對象,而是指向調用該方法的對象。參考我們的例子:我們在el
(按鈕元素)上執行car.getBrand
,而不是它最初定義的car
對象。因此,this
不再指向car
,而是指向el
。如果我們想保持對原始對象的引用不變,同樣,我們需要使用bind()
方法將getBrand()
函數顯式綁定到car
對象。
var car = { brand: "Nissan", getBrand: function() { console.log(this.brand); } }; var el = document.getElementById("btn"); el.addEventListener("click", car.getBrand);
現在,一切按預期工作。
3. 在閉包內使用this
this
的上下文可能出錯的另一個情況是我們在閉包內使用this
。考慮以下示例:
el.addEventListener("click", car.getBrand.bind(car));
這裡的輸出是undefined
,因為閉包函數(內部函數)無法訪問外部函數的this
變量。最終結果是this.brand
等於window.brand
,因為內部函數中的this
綁定到全局對象。為了解決這個問題,我們需要將this
綁定到getBrand()
函數。
var car = { brand: "Nissan", getBrand: function() { var closure = function() { console.log(this.brand); }; return closure(); } }; car.getBrand(); // 输出:undefined
這種綁定等同於car.getBrand.bind(car)
。另一種流行的修復閉包的方法是將this
值賦值給另一個變量,從而防止意外更改。
var car = { brand: "Nissan", getBrand: function() { console.log(this.brand); } }; var getCarBrand = car.getBrand; getCarBrand(); // 输出:undefined
這裡,this
的值可以賦值給_this
、that
、self
、me
、my
、context
、對象的偽名稱或任何其他適合你的名稱。關鍵是保留對原始對象的引用。
ECMAScript 6 的救援
在前面的示例中,我們看到了所謂的“詞法this
”的入門知識——當我們將this
值賦值給另一個變量時。在ECMAScript 6中,我們可以使用類似但更優雅的技術,通過新的箭頭函數來實現。箭頭函數不是由function
關鍵字創建的,而是由所謂的“胖箭頭”運算符(=>
)創建的。與普通函數不同,箭頭函數從其直接封閉作用域獲取this
值。箭頭函數的詞法綁定無法被覆蓋,即使使用new
運算符也是如此。現在讓我們看看如何使用箭頭函數來替換var self = this;
語句。
function(){ console.log(this.brand); }
關於this
需要記住的內容
我們看到this
關鍵字,就像其他任何機制一樣,遵循一些簡單的規則,如果我們很好地了解這些規則,那麼我們可以更自信地使用該機制。因此,讓我們快速回顧一下我們已經學到的內容(來自本文和前文):
this
指向全局對象:this
指向父對象。 call()
或apply()
或bind()
調用函數時,this
指向傳遞給這些方法的第一個參數。如果第一個參數為null
或不是對象,則this
指向全局對象。 new
運算符調用函數時,this
指向新創建的對象。 this
依賴於詞法作用域並指向父對象。 了解這些簡單明了的規則,我們可以輕鬆預測this
將指向什麼,如果它不是我們想要的,我們就知道可以使用哪些方法來修復它。
總結
JavaScript 的this
關鍵字是一個難以掌握的概念,但只要多加練習,你就能掌握它。我希望本文和我的上一篇文章能作為你理解的基礎,並在下次this
讓你頭疼時成為有價值的參考。
JavaScript this
關鍵字的常見問題解答 (FAQs)
(此處省略了FAQs部分,因為篇幅過長,且與前面內容高度重複。FAQs部分內容已在前面詳細解釋。)
以上是掌握JavaScript的最後一步的詳細內容。更多資訊請關注PHP中文網其他相關文章!