本章主題較為輕鬆,討論 JavaScript ES6 箭頭函式(Arrow Function)與一般函式的差異。
一般函式#
ES6 版本之前的 JavaScript 沒有箭頭函式,僅有一般函式。基本語法不再贅述,這裡僅針對幾項容易被忽略的特性說明。
建立#
開發者可以透過 function 及 () 關鍵字來定義、撰寫函式:
function fn() {
// something awesome
}另一種常見的寫法,是宣告一個變數,等號右邊放上函式宣告:
var newFunc = function fn() {
// something awesome
};兩種寫法在使用上唯一的差異,就是第二種寫法在宣告前不能使用。
快問快答小知識:第二種寫法中的
newFunc.name是什麼?答案是fn,而不是newFunc。
另外還有一種透過函數建構子的宣告方法:
var func = new Function("str", "console.log(str)");
func("test");但這種寫法無法利用 JavaScript 引擎事先解析程式並準備 EC 的特性,造成效能浪費,非常不推薦使用。
屬性#
函式在 JavaScript 中,其實是一個可被呼叫(Callable)的物件,除了可執行、擁有例如 apply()、bind()、call() 之類的方法外,也擁有一些函式特有的屬性:
name:函式的名稱。length:可接收參數的數量。
這兩者是 readonly 的屬性,在函式建立後即不能被修改。
另外有兩個已從標準廢棄,但主流瀏覽器仍支援的屬性:
caller:呼叫函式的地方在哪,全域呼叫則回應null。argument:函數執行時所接收到的參數,非執行時呼叫則回傳null。
由於已經是被廢棄的屬性,未來隨時可能會被瀏覽器放棄支援,所以開發上能不用就盡量不用。
另外,在函數執行的過程中,還有一個額外的 arguments 物件可以使用,是一個傳入參數組成的類陣列(Array-like)物件。
被廢棄的是
Function.argument,而非在函式執行時直接呼叫的arguments物件!
this#
this 是讓新手難以捉摸的屬性。預設情況下,函式中的 this 指向呼叫它的物件。
例如以下範例:
function whatIsThis() {
console.log(this);
}
let obj = {
whatIsThis: whatIsThis,
};
whatIsThis(); // window
obj.whatIsThis(); // obj
什麼時候是非預設情況呢?我們可以透過 apply()、bind()、call() 等函式,改變函式的 this。
箭頭函式#
雖然口頭上都稱呼為箭頭函式(Arrow Function),但實際上他是箭頭函式運算式(Arrow Function Expression),指的是類似這樣的語法:
const arrow = (param1, param2) => {
// do something awesome
};由於中間的 => 形似箭頭而得名;且撰寫起來快速直覺,看起來又很潮,深得開發者的喜愛。
建立#
除了前述的語法外,在特定條件下箭頭函式的語法可以進一步簡化:
// 基本用法
const arrow1 = (param1, param2) => {
/* ... */
};
// 僅有一個參數時,可省略括號
const arrow2 = (params) => {
/* ... */
};
// 單一運算後直接回傳時,可省略大括號
const arrow3 = (params) => params ** 2;另外,有一定熟悉度的開發者,可能會利用箭頭函式的特性,撰寫出如下的程式碼:
let fancy = (x) => (y) => (z) => x + y + z;遇到多層的箭頭函式,乍看之下可能會難以理解,但其實只要關注「箭頭」的位置,右到左的反向拆解,並把省略的部分加回去:
let fancy = (x) => {
return (y) => {
return (z) => {
return x + y + z;
};
};
};藉由箭頭函式的各種省略,開發者可以用更短的語法寫出更精簡的程式。
屬性#
與前面說明的一般函式相同,可以取得 name、length 屬性,就不重複說明了。
this#
箭頭函式的重點特色來了:箭頭函式中的 this,會依據函式在哪裡建立而決定,而非與一般函式一樣,依照執行時被呼叫的地方決定。
來看個範例:
var tmp = "a";
var obj = {
tmp: "b",
func: () => console.log(this.tmp),
};
console.log(tmp); // a
obj.func(); // a
由於 obj.func 是在全域環境中建立,this 就被綁定到全域環境中;因此兩個執行結果印出來的結果都是全域變數 tmp 的值 a。
一般函式用來強制綁定
this值的apply()、bind()、call(),在箭頭函式中沒有bind(),且apply()及call()傳入的this值會被忽略,使用時務必特別注意。
結語#
本章針對開發中頻繁使用的一般函式與箭頭函式做說明與比較,希望幫助讀者更進一步認識它們。
原文出處#
- 原書/iThome:https://ithelp.ithome.com.tw/articles/10221214