ES6箭頭函數體中this指向哪裏?

1、this關鍵字小測試

ES6箭頭函數體中的this指向哪裏?

在回答這個問題以前先來揣揣你對this關鍵字的瞭解程度:
(讓咱們回到ES6以前)
題:es6

var obj = {
    a: function() {
        console.log(this);
    }
}

var b = obj.a;
b();

問:打印出的this的值?
再來幾個選項:併發

  1. window
  2. obj
  3. document
  4. obj.a

答案是window(能夠在控制檯運行一下)函數

什麼!什麼狀況!發生了什麼?

一句話解釋:
通常的,this指向函數運行(調用)時所在的執行環境【《JavaScript高級程序設計》4.2節執行環境及做用域】的(變量)對象(簡單地,this指向函數的調用者)測試

分析代碼:this

var b = obj.a;    // ==>至關於
var b = function() {
    console.log(this);
}

函數調用時(b();)其所在的執行環境是全局環境,因此this指向全局變量對象window設計

2、ES6箭頭函數

若是你以爲以上這些都知道了(我會!我會!)那麼就繼續吧~~

(來到ES6箭頭函數)code

例1【阮一峯《ECMAScript 6 入門》-7.函數的擴展:箭頭函數對象

我將阮老師的例子代碼修改了一下:
(普通函數)ip

function foo() {
    console.log("id1:", this.id);
    console.log("this1:", this);
    setTimeout(function() {
        console.log("id2:", this.id);
        console.log("this2:", this);
    }, 0);
}

var id = 21;

foo();

// Chrome
// id1: 21
// this1: window
// id2: 21
// this2: window

foo.call({id: 42});

// Chrome
// id1: 42
// this1: {id: 42}
// id2: 21
// this2: window

注意:超時調用(setTimeout回調)的代碼都是在全局做用域環境中執行的,所以(setTimeout回調)函數中this的值在非嚴格模式下指向window對象,在嚴格模式下是undefined作用域

例如

var obj = {
    console.log(this);
    setTimeout(function() {
        console.log(this);
    }, 0);
}

obj.a();

// Chrome
// {a: f}
// window
回到例1

咱們使用foo函數的call方法改變了foo函數調用時函數體內this的指向({id: 42}這個對象),但setTimeout回調函數中的this依舊指向window對象(由於在全局環境中運行)。

接下來再將例1改寫一下,將foo函數中的setTimeout回調函數改爲箭頭函數的形式:

例2
(箭頭函數)

function foo() {
    console.log("id1:", this.id);
    console.log("this1:", this);
    setTimeout(() => {
        console.log("id2:", this.id);
        console.log("this2:", this);
    }, 0);
}

var id = 21;

foo();

// Chrome
// id1: 21
// this1: window
// id2: 21
// this2: window

foo.call({id: 42});

// Chrome
// id1: 42
// this1: {id: 42}
// id2: 42
// this2: {id: 42}

foo();的輸出結果沒有變化,但foo.call({id: 42});的輸出結果改變了。

到底發生了什麼?

在這裏直接給出結論:
箭頭函數根本沒有本身的this,致使內部的this指向了外層代碼的this這個指向在定義時就已經肯定而不會在調用時指向其執行環境的(變量)對象

注意:由於箭頭函數內部的this是指向外層代碼塊的this(最近的this,例2中的foo函數)的,因此咱們能夠經過改變外層代碼塊的this的指向從而改變箭頭函數中this的指向(例2中使用了foo函數的call方法)。

從新解釋例2

由於箭頭函數(setTimeout回調)沒有本身的this,致使其內部的this引用了外層代碼塊的this,即foo函數的this

(要注意:在定義階段(調用函數前),foo函數的this的值並不肯定【《JavaScript高級程序設計》第三版5.5.4函數內部屬性】,但箭頭函數的this自定義階段開始就指向foo函數的this了)

又由於使用call方法改變了foo函數運行(調用)時其函數體內this的指向(從新指向對象{id: 42})從而使箭頭函數中this的指向發生變化,最後輸出例2所示結果。

3、例子總結

到這裏,我想小夥伴們應該是比較清楚了,那麼不妨去看看阮一峯老師的《ECMAScript 6 入門》函數的擴展一節箭頭函數部分的一個問題示例:「請問下面的代碼中有幾個this(滑稽)

加深印象

例3【阮一峯《ECMAScript 6 入門》-19.Class基本語法:this的指向

class Logger {
  constructor() {
    this.printName = (name = 'there') => {
      this.print(`Hello ${name}`);
    };
  }

  // ...
}

箭頭函數中的this指向constructor構造方法內部的this,因爲此時constructor中的this還沒有得到值,當經過new命令生成對象實例時,將會自動調用constructor方法,constructorthis才能指向該實例對象,在此過程當中,箭頭函數中的this一直引用着constructor中的this,當constructorthis發生變化,箭頭函數的this也會一併發生變化。

如有錯誤,請指出批評!!
相關文章
相關標籤/搜索