首頁 > web前端 > js教程 > JS 中幾種處理'this'指向的方式

JS 中幾種處理'this'指向的方式

發布: 2020-06-18 17:18:03
轉載
2036 人瀏覽過

JS 中幾種處理'this'指向的方式

我喜歡在JS中更改函數執行上下文的指向,也稱為 this 指向。

例如,咱們可以在類別數組物件上使用數組方法:

const reduce = Array.prototype.reduce;

function sumArgs() {
  return reduce.call(arguments, (sum, value) => {
    return sum += value;
  });
}

sumArgs(1, 2, 3); // => 6
登入後複製

另一方面,this 很難掌握。

咱們常常會發現自己用的 this 指向不正確。下面的教你如何簡單地將 this 綁定到所需的值。

在開始之前,我需要一個輔助函數execute(func),它只執行作為參數提供的函數。

function execute(func) {
  return func();
}

execute(function() { return 10 }); // => 10
登入後複製

現在,繼續理解圍繞this錯誤的本質:方法分離。

1.方法分離問題

假設有一個類別Person包含欄位firstNamelastName。此外,它還有一個方法getFullName(),該方法傳回此人的全名。如下圖所示:

function Person(firstName, lastName) {
  this.firstName = firstName;
  this.lastName = lastName;

  this.getFullName = function() {
    this === agent; // => true
    return `${this.firstName} ${this.lastName}`;
  }
}

const agent = new Person('前端', '小智');
agent.getFullName(); // => '前端 小智'
登入後複製

可以看到Person函數作為建構子被呼叫:new Person('前端', '小智')。函數內部的 this 表示新建立的實例。

getfullname()傳回此人的全名:'前端 小智'。如預期的那樣,getFullName()方法內的 this 等於agent

如果輔助函數執行agent.getFullName方法會發生什麼:

execute(agent.getFullName); // => 'undefined undefined'
登入後複製

執行結果不正確:'undefined undefined',這是this 指向不正確導致的問題。

現在在getFullName() 方法中,this的值是全域物件(瀏覽器環境中的 window )。 this 等於 window${window.firstName} ${window.lastName} 執行結果是 'undefined undefined'

發生這種情況是因為在呼叫execute(agent.getFullName)時該方法與物件分離。基本上發生的只是常規函數呼叫(不是方法呼叫):

execute(agent.getFullName); // => 'undefined undefined'

// 等价于:

const getFullNameSeparated = agent.getFullName;
execute(getFullNameSeparated); // => 'undefined undefined'
登入後複製

這個就是所謂的方法從它的物件中分離出來,當方法被分離,然後執行時,this與原始物件沒有連接。

為了確保方法內部的this指向正確的對象,必須這樣做

  1. 以屬性存取器的形式執行方法: agent.getFullName()

  2.         或靜態地​​將this綁定到包含的物件(使用箭頭函數、.bind()方法等)

方法分離問題,以及由此導致this指向不正確,一般會在下面的幾種情況中出現:

##
// `methodHandler()`中的`this`是全局对象
setTimeout(object.handlerMethod, 1000);
登入後複製

在設定事件處理程序時

// React: `methodHandler()`中的`this`是全局对象
<button onClick={object.handlerMethod}>
  Click me
</button>
登入後複製

接著介紹一些有用的方法,即如果方法與物件分離,如何使this指向所需的物件。

2. 關閉上下文

保持this指向類別實例的最簡單方法是使用一個額外的變數self :

function Person(firstName, lastName) {
  this.firstName = firstName;
  this.lastName = lastName;

  const self = this;

  this.getFullName = function() {
    self === agent; // => true
    return `${self.firstName} ${self.lastName}`;
  }
}

const agent = new Person(&#39;前端&#39;, &#39;小智&#39;);

agent.getFullName();        // => &#39;前端 小智&#39;
execute(agent.getFullName); // => &#39;前端 小智&#39;
登入後複製

getFullName()靜態地關閉self變量,有效地對this進行手動綁定。

現在,當呼叫execute(agent.getFullName)時,一切都運作正常,因為getFullName()方法內 this# 總是指向正確的值。

3.使用箭頭函數

有沒有辦法在沒有附加變數的情況下靜態綁定this?是的,這正是箭頭函數的作用。

使用箭頭函數重構Person:

function Person(firstName, lastName) {
  this.firstName = firstName;
  this.lastName = lastName;

  this.getFullName = () => `${this.firstName} ${this.lastName}`;
}

const agent = new Person(&#39;前端&#39;, &#39;小智&#39;);

agent.getFullName();        // => &#39;前端 小智&#39;
execute(agent.getFullName); // => &#39;前端 小智&#39;
登入後複製

箭頭函數以詞法方式綁定this。簡單來說,它使用來自其定義的外部函數this的值。

建議在需要使用外部函數上下文的所有情況下都使用箭頭函數。

4. 綁定上下文

現在讓咱們更進一步,使用ES6中的類別重構Person

class Person {
  constructor(firstName, lastName) {
    this.firstName = firstName;
    this.lastName = lastName;
  }

  getFullName() {
    return `${this.firstName} ${this.lastName}`;
  }
}

const agent = new Person('前端', '小智');

agent.getFullName();        // => '前端 小智'
execute(agent.getFullName); // => &#39;undefined undefined&#39;
登入後複製

不幸的是,即使使用新的類別語法,execute(agent.getFullName)仍然傳回「undefined undefined」

在類別的情況下,使用附加的變數self或箭頭函數來修復this的指向是行不通的。

但有一個涉及bind()方法的技巧,它將方法的上下文綁定到建構函式中:

class Person {
  constructor(firstName, lastName) {
    this.firstName = firstName;
    this.lastName = lastName;

    this.getFullName = this.getFullName.bind(this);
  }

  getFullName() {
    return `${this.firstName} ${this.lastName}`;
  }
}

const agent = new Person(&#39;前端&#39;, &#39;小智&#39;);

agent.getFullName();        // => &#39;前端 小智&#39;
execute(agent.getFullName); // => &#39;前端 小智&#39;
登入後複製

建構子中的this .getFullName = this.getFullName.bind(this)將方法getFullName()綁定到類別實例。

execute(agent.getFullName) 按預期工作,返回'前端 小智'

5. 胖箭頭法

bind 方式有點太冗長,咱們可以使用胖箭頭的方式:

class Person {
  constructor(firstName, lastName) {
    this.firstName = firstName;
    this.lastName = lastName;
  }

  getFullName = () => {
    return `${this.firstName} ${this.lastName}`;
  }
}

const agent = new Person(&#39;前端&#39;, &#39;小智&#39;);

agent.getFullName();        // => &#39;前端 小智&#39;
execute(agent.getFullName); // => &#39;前端 小智&#39;
登入後複製

胖箭头方法getFullName =() =>{…}绑定到类实例,即使将方法与其对象分离。

这种方法是在类中绑定this的最有效和最简洁的方法。

6. 总结

与对象分离的方法会产生 this 指向不正确问题。静态地绑定this,可以手动使用一个附加变量self来保存正确的上下文对象。然而,更好的替代方法是使用箭头函数,其本质上是为了在词法上绑定this

在类中,可以使用bind()方法手动绑定构造函数中的类方法。当然如果你不用使用 bind 这种冗长方式,也可以使用简洁方便的胖箭头表示方法。

更多JavaScript知识请关注PHP中文网JavaScript视频教程栏目

以上是JS 中幾種處理'this'指向的方式的詳細內容。更多資訊請關注PHP中文網其他相關文章!

相關標籤:
來源:csdn.net
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
最新問題
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板