關於深入理解JavaScript中的箭頭函式

才智咖 人氣:2.51W

從一開始箭頭就是 JavaScript 的一部分,在第一個 JavaScript 中就建議將內聯的指令碼程式碼包裹在 HTML 的註釋中,這可以防止那些不支援 JavaScript 的瀏覽器錯誤滴將你的程式碼顯示為明文。你也許寫過下面這樣的程式碼:

關於深入理解JavaScript中的箭頭函式

古老的瀏覽器將看到兩個不被支援的標籤和一段註釋,只有支援 JavaScript 的新瀏覽器才會將其解析為 JavaScript 程式碼。

為了支援這個古怪的特性,瀏覽器的 JavaScript 引擎把  也表示一個單行註釋,與 HTML 不同的是,在 HTML 中,--> 之前的部分是註釋內容,而在 JavaScript 中,在 --> 之後的行才是註釋。

只有當 --> 出現在一行的開始時,才表示該箭頭是一個註釋,因為在其他情況下,--> 是一個操作符(goes to)。

function countdown(n) { while (n-->0) // "n goes to zero" alert(n); blastoff();} function countdown(n) { while (n-->0) // "n goes to zero" alert(n); blastoff();}

上面程式碼是真實能執行的。迴圈執行直到 n 為 0,這並不是 ES6 的新特性,但結合我們熟悉的特性,這具有很強的誤導性。你能搞明白上面程式碼的執行情況嗎?你可以在 Stack Overflow 上找到相應的解答。

當然還有一個箭頭,那就是小於等於操作符 <=,也許你還可以找到使用箭頭的.地方,但我們還是停下來,看一個我們從沒見過的箭頭:

goes to 操作符 <=> ???

那麼,=> 表示什麼呢?這就是本文將討論的話題。

首先,我們來談談函式。

無處不在的函式表示式

JavaScript 一個有趣的特點是,任何時候你需要一個函式,你可以很方便地建立它們。

例如,為一個按鈕繫結點選事件:

$("#confetti-btn")k( $("#confetti-btn")k(

jQuery 的 k() 方法需要一個函式作為引數,我們可以很方便地就地建立一個函式:

$("#confetti-btn")k(function (event) { playTrumpet(); fireConfettiCannon();}); $("#confetti-btn")k(function (event) { playTrumpet(); fireConfettiCannon();});

現在對我們來說,編寫這樣的程式碼是最自然的事了。但是在 JavaScript 流行起來之前,這種風格的程式碼看起來還是有些奇怪,因為在其他語言中都沒有這樣的特性。在 1958 年,Lisp 就有了函式表示式,也叫 lambda 函式,而在存在多年的 C++、Python、C# 和 Java 中沒有該特性。

現在,這四門語言都有了 lambda 表示式,而且新出現的語言都普遍內建了 lambda 表示式。如今 JavaScript 也支援該特性了,這必須感謝那些重度依賴 lambda 表示式的庫的開發者,這推動了該特性被廣泛採納。

與其他幾門語言相比,JavaScript 的語法略顯冗長:

// A very simple function in six tion (a) { return a > 0; } // JS[](int a) { return a > 0; } // C++(lambda (a) (> a 0)) ;; Lisplambda a: a > 0 # Pythona => a > 0 // C#a -> a > 0 // Java // A very simple function in six tion (a) { return a > 0; } // JS[](int a) { return a > 0; } // C++(lambda (a) (> a 0)) ;; Lisplambda a: a > 0 # Pythona => a > 0 // C#a -> a > 0 // Java

箭頭函式

ES6 引入了一種新的語法來編寫函式:

// ES5var selected = er(function (job) { return lected();});// ES6var selected = er(job => lected()); // ES5var selected = er(function (job) { return lected();}); // ES6var selected = er(job => lected());

當你需要只有一個引數的函式,箭頭函式的語法可以簡化為 Identifier => Expression,直接省略了 function 和 return 關鍵字,連括號和結尾的分號也同時省略了。

編寫一個有多個(或沒有引數,或 Rest 引數和引數預設值,或解構引數)引數的函式,你需要用括號將引數括起來:

// ES5var total = ce(function (a, b) { return a + b;}, 0);// ES6var total = ce((a, b) => a + b, 0); // ES5var total = ce(function (a, b) { return a + b;}, 0); // ES6var total = ce((a, b) => a + b, 0);

箭頭函式還可以與一些工具函式庫完美地配合使用,比如 和 Immutable,事實上,Immutable 文件中的例子全部都是使用 ES6 編寫,其中有很多已經使用到了箭頭函式。

函式體除了使用一個表示式外,箭頭函式還可以包含一個語句塊,回憶之前我們提到過的例子:

// ES5$("#confetti-btn")k(function (event) { playTrumpet(); fireConfettiCannon();}); // ES5$("#confetti-btn")k(function (event) { playTrumpet(); fireConfettiCannon();});

下面是採用箭頭函式的寫法:

// ES6$("#confetti-btn")k(event => { playTrumpet(); fireConfettiCannon();}); // ES6$("#confetti-btn")k(event => { playTrumpet(); fireConfettiCannon();});

需要注意的是,使用語句塊的箭頭函式不會自動返回一個值,必須顯式地使用 return 來返回一個值。

還有一個忠告,當使用箭頭函式來返回一個物件時,始終使用括號將返回的物件括起來:

// create a new empty object for each puppy to play withvar chewToys = (puppy => {}); // BUG!var chewToys = (puppy => ({})); // ok // create a new empty object for each puppy to play withvar chewToys = (puppy => {}); // BUG!var chewToys = (puppy => ({})); // ok

因為空物件 {} 與空語句塊 {} 看上去一模一樣,ES6 將始終把緊跟在 => 後面的 { 當作語句塊的開始,而不是一個物件的開始,那麼 puppy => {} 就被解析為一個沒有函式體的箭頭函式,而且返回值為 undefined。

TAGS:箭頭 函式