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/
箭頭函式的理論知識
介紹
箭頭函式表示式的語法比函式表示式更短,並且沒有自己的this,arguments,super或 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
關鍵字,再之沒有使用bind
, call
和apply
。setInterval
只是一個普通的函式。實際上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;
最後總結兩點就是
- 箭頭函式寫程式碼擁有更加簡潔的語法;
- 不會繫結
this
。