1. 程式人生 > >JavaScript:學習筆記(5)——箭頭函式=>以及實踐

JavaScript:學習筆記(5)——箭頭函式=>以及實踐

JavaScript:學習筆記(5)——箭頭函式=>以及實踐

ES6標準新增了一種新的函式:Arrow Function(箭頭函式)。本文參考的連結如下:

  • MDN箭頭函式:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Functions/Arrow_functions
  • 廖雪峰箭頭函式:https://www.liaoxuefeng.com/wiki/.......
  • FunDebug的文章:https://blog.fundebug.com/2017/05/25/arrow-function-for-beginner/

箭頭函式的理論知識

介紹

  箭頭函式表示式的語法比函式表示式更短,並且沒有自己的thisargumentssuper或 new.target。這些函式表示式更適用於那些本來需要匿名函式的地方,並且它們不能用作建構函式

  箭頭函式相當於匿名函式,並且簡化了函式定義。箭頭函式有兩種格式,一種像下面這樣,只包含一個表示式,連{ ... }return都省略掉了

x => x * x

/*上面的箭頭函式相當於*/

function (x) {
    return x * x;
}

  還有一種可以包含多條語句,這時候就不能省略{ ... }

return

x => {
    if (x > 0) {
        return x * x;
    }
    else {
        return - x * x;
    }
}

  如果要返回一個物件,就要注意,如果是單表示式,這麼寫的話會報錯:

// SyntaxError:
x => { foo: x }

  故返回物件時函式體的{ ... }有語法衝突,所以要改為({....})

// ok:
x => ({ foo: x })

  其語法結構可總結如下:

(引數1, 引數2, …, 引數N) => { 函式宣告 }
(引數1, 引數2, …, 引數N) => 表示式(單一)
//相當於:(引數1, 引數2, …, 引數N) =>{ return 表示式; }

// 當只有一個引數時,圓括號是可選的:
(單一引數) => {函式宣告}
單一引數 => {函式宣告}

// 沒有引數的函式應該寫成一對圓括號。
() => {函式宣告}
//加括號的函式體返回物件字面表示式:
引數=> ({foo: bar}) //支援剩餘引數和預設引數 (引數1, 引數2, ...rest) => {函式宣告} (引數1 = 預設值1,引數2, …, 引數N = 預設值N) => {函式宣告} //同樣支援引數列表解構 let f = ([a, b] = [1, 2], {x: c} = {x: a + b}) => a + b + c; f(); // 6

關於this

  和一般的函式不同,箭頭函式不會繫結this。 或則說箭頭函式不會改變this本來的繫結
  我們用一個例子來說明:

function Counter() {
  this.num = 0;
}
var a = new Counter();  

  因為使用了關鍵字new構造,Count()函式中的this繫結到一個新的物件,並且賦值給a。通過console.log列印a.num,會輸出0。即

console.log(a.num);
// 0

  如果我們想每過一秒將a.num的值加1,該如何實現呢?可以使用setInterval()函式。

function Counter() {
  this.num = 0;
  this.timer = setInterval(function add() {
    this.num++;
    console.log(this.num);
  }, 1000);
}

  我們來看一下輸出結果:

var b = new Counter();
// NaN
// NaN
// NaN
// ...

  你會發現,每隔一秒都會有一個NaN打印出來,而不是累加的數字。到底哪裡錯了呢?首先函式setInterval沒有被某個宣告的物件呼叫,也沒有使用new關鍵字,再之沒有使用bindcallapplysetInterval只是一個普通的函式。實際上setInterval裡面的this繫結到全域性物件的。我們可以通過將this打印出來驗證這一點:

  回到之前的函式,之所以列印NaN,是因為this.num繫結到window物件的num,而window.num未定義

  那麼,我們如何解決這個問題呢?使用箭頭函式!使用箭頭函式就不會導致this被繫結到全域性物件

function Counter() {
  this.num = 0;
  this.timer = setInterval(() => {
    this.num++;
    console.log(this.num);
  }, 1000);
}
var b = new Counter();
// 1
// 2
// 3
// ...

  通過Counter建構函式繫結的this將會被保留。在setInterval函式中,this依然指向我們新建立的b物件

  其實這裡也為了一個持續困擾我的問題,即是一種hack寫法。 

var that = this;

最後總結兩點就是

  1. 箭頭函式寫程式碼擁有更加簡潔的語法
  2. 不會繫結this。