this總結

行走的羊駝駝發表於2018-12-15

全域性環境中this

.node中this相當於全域性物件 global。 .在JavaScript檔案中, this等同於 module.exports而不是 global。

函式中的this 函式中的 this值通常是由函式的呼叫方來定義。

function rajat() {
  //this === window
}
複製程式碼

方法中的“this”

當函式作為物件的方法被呼叫時, this指向的是該物件,也稱為函式呼叫的接收器(receiver)。

const hero = {
  heroName: "Batman",
  dialogue() {
    console.log(`I am ${this.heroName}!`);
  }
};
hero.dialogue();
複製程式碼

建構函式中的“this”

建構函式被呼叫時,會建立一個新物件並將其設定為函式的 this引數。建構函式會隱式的返回這個物件,除非我們明確的返回了另外一個物件。 在 hero函式內部新增下面的 return語句:

function Hero(heroName, realName) {
   return {
      heroName: "Batman",
      realName: "Bruce Wayne",
    };
}
new Hero();//{heroName: "Batman", realName: "Bruce Wayne"}


function Hero(heroName, realName) {
      heroName: "Batman";
      realName: "Bruce Wayne";
}
new Hero();//Hero {}
複製程式碼

call() 和 apply()

在呼叫函式時也可以使用 call()和 apply()明確設定 this引數。

function dialogue () {
  console.log (`I am ${this.heroName}`);
}
const hero = {
  heroName: 'Batman',
};
複製程式碼

如果要將 hero物件作為 dialogue函式的接收器,我們可以這樣使用 call()或 apply() :

dialogue.call(hero)
// or
dialogue.apply(hero)
複製程式碼

bind()

當我們將一個方法作為回撥函式傳遞給另一個函式時,總是存在丟失方法的原有接收器的風險,使得 this引數指向全域性物件。 bind()方法可以將 this引數固定的繫結到一個值上。 下面的程式碼片段, bind會建立一個新的 dialogue函式,並將 this值設定為 hero 。 (譯者注:bind()方法會建立一個新函式,稱為繫結函式-bound function-BF,當呼叫這個繫結函式時,繫結函式會以建立它時傳入 bind()方法的第一個引數作為 this,傳入 bind() 方法的第二個以及以後的引數加上繫結函式執行時本身的引數按照順序作為原函式的引數來呼叫原函式。)

const hero = {
  heroName: "Batman",
  dialogue() {
    console.log(`I am ${this.heroName}`);
  }
};
setTimeOut(hero.dialogue.bind(hero), 1000);
複製程式碼

使用 call或 apply方法也無法改變 this的值 。

箭頭函式中的“this”

箭頭函式引用的是箭頭函式在建立時設定的 this值,不是執行時環境this。 箭頭函式會永久地捕獲 this值,阻止 apply或 call後續更改它。 為了解釋箭頭函式中的 this是如何工作的,我們來寫一個箭頭函式:

const batman = this;
const bruce = () => {
  console.log(this === batman);//true
};
bruce();
複製程式碼

(譯者注:箭頭函式中沒有this繫結,必須通過查詢作用域鏈來決定它的值,如果箭頭函式被非箭頭函式包裹,那麼this值由外圍最近一層非箭頭函式決定,否則為undefined。) 箭頭函式也不能用作建構函式。因此,我們也不能在箭頭函式內給 this設定屬性。 那麼箭頭函式對 this 可以做什麼呢? 箭頭函式可以使我們在回撥函式中訪問 this 。

const counter = {
  count: 0,
  increase() {
    setInterval(function() {
      console.log(++this.count);
      //只會得到一個 NaN的列表。這是因為 this.count已經不是指向 counter物件了。
      //它實際上指向的為 global物件。
    }, 1000);
  }
}
counter.increase();
//使用箭頭函式
const counter = {
  count: 0,
  increase () {
    setInterval (() => {
      console.log (++this.count);
    }, 1000);
  },
};
counter.increase();
複製程式碼

Class中的“this”

類通常包含一個 constructor , this可以指向任何新建立的物件。 不過在作為方法時,如果該方法作為普通函式被呼叫, this也可以指向任何其他值。與方法一樣,類也可能失去對接收器的跟蹤。

class Hero {
  constructor(heroName) {
    this.heroName = heroName;
  }
  dialogue() {
    console.log(`I am ${this.heroName}`)
  }
}
const batman = new Hero("Batman");
batman.dialogue();
複製程式碼

建構函式裡的 this指向新建立的 類例項。當我們呼叫 batman.dialogue()時, dialogue()作為方法被呼叫, batman是它的接收器。 但是如果我們將 dialogue()方法的引用儲存起來,並稍後將其作為函式呼叫,我們會丟失該方法的接收器,此時 this引數指向 undefined 。

const say = batman.dialogue;
say();
複製程式碼

出現錯誤的原因是JavaScript 類是隱式的執行在嚴格模式下的。我們是在沒有任何自動繫結的情況下呼叫 say()函式的。要解決這個問題,我們需要手動使用 bind()將 dialogue()函式與 batman繫結在一起。

const say = batman.dialogue.bind(batman);
say();
複製程式碼

我們也可以在 建構函式方法中做這個繫結。