關於ES6中箭頭函數的this問題

什麼是箭頭函數

用法

ES6 容許使用「箭頭」(=>)定義函數javascript

<p id="test1">測試</p>

  var p1 = document.getElementById('test1');
  p1.addEventListener('click', () => {
        p1.style.color = "red";
     }, false);

在es5中至關於java

var p1 = document.getElementById('test1');
   p1.addEventListener('click', function () {
             //直接經過dom的方法改變顏色
             this.style.color = "red"; 
      },false);

可是咱們思考一個問題——當咱們把第一段代碼中的p1換成this時
this會指向哪裏app

p1.addEventListener('click', () => {
         
      this.style.color = "red";//   'color' is not undefined
     }, false);

這時咱們就會想this爲何沒有做用,而在es5中this是指向了p1dom

箭頭函數有個使用注意點。

函數體內的this對象,就是定義時所在的對象,而不是使用時所在的對象。
this對象的指向是可變的,可是在箭頭函數中,它是固定的。函數

function foo() {
  setTimeout(() => {
    console.log('id:', this.id);
  }, 100);
}

var id = 21;

foo.call({ id: 42 });
// id: 42

上面代碼中,setTimeout的參數是一個箭頭函數,這個箭頭函數的定義生效是在foo函數生成時,而它的真正執行要等到100毫秒後。若是是普通函數,執行時this應該指向全局對象window,這時應該輸出21。可是,箭頭函數致使this老是指向函數定義生效時所在的對象(本例是{id: 42}),因此輸出的是42學習

箭頭函數的this

this指向的固定化,並非由於箭頭函數內部有綁定this的機制,實際緣由是箭頭函數根本沒有本身的this,致使內部的this就是外層代碼塊的this。正是由於它沒有this,因此也就不能用做構造函數測試

// ES6
function foo() {
  setTimeout(() => {
    console.log('id:', this.id);
  }, 100);
}

// ES5
function foo() {
  var _this = this;

  setTimeout(function () {
    console.log('id:', _this.id);
  }, 100);
}

上面代碼中,轉換後的es5清楚地說明了,箭頭函數裏面根本沒有本身的this,而是引用外層的this。this

因爲箭頭函數沒有本身的this,因此固然也就不能用call()、apply()、bind()這些方法去改變this的指向。es5

(function() {
  return [
    (() => this.x).bind({ x: 'inner' })()
  ];
}).call({ x: 'outer' });
// ['outer']

一樣的因爲箭頭函數沒有本身的this 因此bind傳統的顯性綁定無效 內部的this指向外部this
在javascript的學習中, this的指向問題一直是個難點,特別是在對象方法中使用this時,必須更加當心。由此箭頭函數在很大程度上減小了咱們的困擾。code

箭頭函數this詞法

話又說回來,當咱們使用箭頭函數時不使用常規的四種this綁定,又該怎麼決定this的指向問題呢?
箭頭函數是根據外層(函數或者全局)做用域來決定this

讓咱們看看箭頭函數的此法做用域:

function foo() {
            //返回箭頭函數
            return(a) => {
                //this 繼承自foo()
                console.log(this.a);
            };
        }
        var obj1 = {
            a:2
        };
        var obj2 ={
            a:3
        };
        var bar = foo.call(obj1);
        bar.call(obj2); //是2, 不是3!!!

foo()內部建立的箭頭函數會捕獲調用時foo()的this。因爲foo()的this綁定到了obj1,因此bar(引用箭頭函數)的this也會綁定到obj1,上文說過箭頭函數this對象的指向是固定的因此後面的call修改不了綁定,即便是new也不行。

箭頭函數能夠像bind()同樣確保函數的this被綁定到指定對象上,此外, 其重要性還體如今它更常見的詞法做用域取代了傳統的this的機制。實際上, 在ES6以前咱們就已經在使用一種集合和箭頭函數徹底同樣的模式了。

function foo() {
            var self = this;
            setTimeout(function() {
                console.log(self.a)
            },100)
        }
        var obj = {
            a:2
        };
        foo.call(obj);

和箭頭函數同樣self = this 看起來均可以取代bind(), 可是從本質上來看,它們是想代替this這個機制。

注意

若是常常編寫this風格的代碼,又喜歡用箭頭函數或者self= this的方法來否認this機制。
那麼或許你應當:

  1. 只使用詞法做用域並徹底摒棄錯誤的this風格
  2. 徹底採用this風格,在必要時仍使用bind(), 避免使用箭頭函數或者self = this。
相關文章
相關標籤/搜索