JavaScript >> Javascript 文檔 >  >> Tags >> this

掌握 JavaScript 的“this”關鍵字的最後步驟

在上一篇文章中,我們學習了使用 JavaScript 的 this 的基礎知識 關鍵字正確。我們看到了決定 this 的關鍵因素 指,就是找出當前的執行上下文。但是,在上下文以我們未預料到的方式發生變化的情況下,此任務可能會有些棘手。在本文中,我將重點介紹何時會發生這種情況以及我們可以採取哪些措施來補救。

修復常見問題

在本節中,我們將探討使用 this 引起的一些最常見的問題 關鍵字,我們將學習如何修復它們。

1.使用 this 在提取方法中

人們最常犯的錯誤之一是嘗試將對象的方法分配給變量並期望 this 仍將指向原始對象。從下面的例子中我們可以看出,這根本行不通。

var car = {
brand: "Nissan",
getBrand: function(){
console.log(this.brand);
}
};

var getCarBrand = car.getBrand;

getCarBrand(); // output: undefined

JS斌

即使 getCarBrand 似乎是對 car.getBrand() 的引用 ,其實只是對getBrand()的另一種引用 本身。我們已經知道調用站點在確定上下文時很重要,這裡的調用站點是 getCarBrand() ,這是一個簡單明了的函數調用。

證明getCarBrand 指向一個無基礎的函數(不綁定到任何特定對象的函數),只需添加 alert(getCarBrand); 到代碼底部,你會看到如下輸出:

function(){
console.log(this.brand);
}

getCarBrand 只包含一個普通函數,它不再是 car 的方法 目的。所以,在這種情況下,this.brand 實際上轉換為 window.brand ,當然是 undefined .

如果我們從一個對像中提取一個方法,它又會變成一個普通的函數。它與對象的連接被切斷,不再按預期工作。換句話說,提取的函數並沒有綁定到它所取自的對象。

那麼我們該如何補救呢?好吧,如果我們想保留對原始對象的引用,我們需要顯式綁定 getBrand() car 的函數 當我們將對象分配給 getCarBrand 多變的。我們可以使用 bind() 方法來做到這一點。

var getCarBrand = car.getBrand.bind(car);
getCarBrand(); // output: Nissan

現在,我們得到了正確的輸出,因為我們成功地將上下文重新定義為我們想要的樣子。

2 this 在回調中使用

當我們傳遞一個方法(使用 this 作為參數)用作回調函數。例如:

<button id="btn" type="button">Get the car's brand</button>

var car = {
brand: "Nissan",
getBrand: function(){
console.log(this.brand);
}
};

var el = document.getElementById("btn");
el.addEventListener("click", car.getBrand);

JS斌

即使我們使用 car.getBrand , 我們實際上只得到函數 getBrand() 附加到 button 對象。

將參數傳遞給函數是一種隱式賦值,因此這裡發生的情況與前面的示例幾乎相同。不同的是現在 car.getBrand 不是顯式分配的,而是隱式分配的。結果幾乎相同——我們得到的是一個普通函數,綁定到 button 對象。

換句話說,當我們對一個與最初定義該方法的對像不同的對象執行方法時,this 關鍵字不再引用原始對象,而是調用該方法的對象。

參考我們的例子:我們正在執行 car.getBrandel (按鈕元素),而不是 car 對象,它最初是在該對像上定義的。因此,this 不再引用 car ,而不是 el .

如果我們想保持對原始對象的引用不變,我們需要顯式綁定 getBrand() car 的函數 對象使用 bind() 方法。

el.addEventListener("click", car.getBrand.bind(car));

現在,一切正常。

3 this 用於內部封閉

this 的另一個實例 當我們使用 this 時,可能會誤認為上下文 封閉的內部。考慮以下示例:

var car = {
brand: "Nissan",
getBrand: function(){
var closure = function(){
console.log(this.brand);
};
return closure();
}
};

car.getBrand(); // output: undefined

JS斌

在這裡,我們得到的輸出是 undefined ,因為閉包函數(內部函數)無法訪問 this 外部函數的變量。最終結果是 this.brand 等於 window.brand ,因為 this in 內部函數綁定到全局對象。

為了解決這個問題,我們需要保留 this 綁定到 getBrand() 功能。

var car = {
brand: "Nissan",
getBrand: function(){
var closure = function(){
console.log(this.brand);
}.bind(this);
return closure();
}
};

car.getBrand(); // output: Nissan

JS斌

此綁定等效於 car.getBrand.bind(car) .

修復閉包的另一種流行方法是分配 this 值到另一個變量,從而防止不必要的變化。

var car = {
brand: "Nissan",
getBrand: function(){
var self = this;
var closure = function(){
console.log(self.brand);
};
return closure();
}
};

car.getBrand(); // output: Nissan

JS斌

這裡,this的值 可以分配給 _this , that , self , me , my , context ,對象的偽名稱,或任何其他適合你的東西。重點是保持對原始對象的引用。

ECMAScript 6 救援

在前面的示例中,我們看到了所謂的“lexical this “——當我們設置 this 值到另一個變量。在 ECMAScript 6 中,我們可以使用類似但更優雅的技術,通過新的箭頭函數應用。

箭頭函數不是由 function 創建的 關鍵字,而是通過所謂的“胖箭頭”運算符(=> )。與常規函數不同,箭頭函數採用 this 從它們的直接封閉範圍中獲取價值。箭頭函數的詞法綁定不能被覆蓋,即使使用 new 運營商。

現在讓我們看看如何使用箭頭函數代替 var self = this; 聲明。

var car = {
brand: "Nissan",
getBrand: function(){
// the arrow function keeps the scope of "this" lexical
var closure = () => {
console.log(this.brand);
};
return closure();
}
};

car.getBrand(); // output: Nissan

JS斌

您需要記住的關於 this

我們看到 this 關鍵字和其他機制一樣,遵循一些簡單的規則,如果我們熟悉它們,那麼我們可以更有信心地使用該機制。所以,讓我們快速回顧一下我們學到的東西(從這篇文章和上一篇文章中):

  • this 在以下情況下指的是全局對象:
    • 在最外層的上下文中,在任何功能塊之外
    • 在不是對象方法的函數中
    • 在不是對象構造函數的函數中
  • 當函數作為父對象的屬性調用時,this 引用父對象。
  • 當使用 call() 調用函數時 或 apply() , 或 bind() , this 指傳遞給這些方法的第一個參數。如果第一個參數是 null 或不是一個對象,this 指的是全局對象。
  • 使用 new 調用函數時 運算符,this 指的是新創建的對象。
  • 當使用箭頭函數(ECMAScript 6 中引入)時,this 依賴於詞法範圍並引用父對象。

知道了這些直截了當的規則,我們就可以輕鬆預測出this 將指向,如果它不是我們想要的,我們知道我們可以使用哪些方法來修復它。

總結

JavaScript 的 this 關鍵字是一個很難掌握的概念,但只要有足夠的練習,你就可以掌握它。我希望這篇文章和我之前的文章,作為你理解的一個很好的基礎,並在下次this的時候證明是一個有價值的參考。 讓你頭疼。


Tutorial JavaScript 教程
  1. 正則表達式匹配任何 js 數字

  2. jQuery/AJAX - 單擊按鈕時將內容加載到 div 中?

  3. 如何避免 Javascript 錯誤

  4. React Simple Compont 不在瀏覽器內呈現

  5. 將 2D JavaScript 數組轉換為 1D 數組

  6. 使用 GitHub Actions 設置從 NodeJS 到 AWS Lambda 的 CD 工作流程

  7. QuerySnapshot.empty 導致承諾拒絕錯誤

  1. 盡可能簡單地解釋微前端

  2. 帶有 React 的無頭 WordPress

  3. 🌍Secret Unicorn Password (JS+Console) [YouTube LIVE]

  4. 使用反應打字稿和反應測試庫做列表應用程序

  5. ZeroMQ 和 Node.js 教程 - 破解 JWT 令牌(第 1 部分。)

  6. iframe 中的後退和前進按鈕

  7. 使用 CreateJS 的豐富演示

  1. 通過學習 Closure(背包類比)來完成你的面試!

  2. JavaScript ES6:改進代碼的 5 個新抽象

  3. Material UI Datepicker 和 @date-io/date-fns 2.0.0

  4. 如何創建具有多個模塊的多個減速器?