# function and arrow function ###### tags: `Javascript` `note` 通常講到 function 跟 arrow function,我們主要都在談論他們之間的差異,arrow function 雖然簡單,但是相對於一般 function 有一些功能上的限制,了解其差異可以幫助我們在開發上作選擇。 ### function 建立 function 會有兩種作法,一個是 declaration,另一個是 expression,我們先來看 declaration。 [**function declaration**](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function) >A function created with a function declaration is a `Function` object and has all the properties, methods and behavior of `Function` objects. See [`Function`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function) for detailed information on functions. ```js function foo(a, b){ return a + b; } ``` 根據 MDN 解釋,一般的 function 宣告本質上都是幫你建立一個 `Function` 物件,既然他是物件,那肯定會有一些屬性,我們來看他有哪些屬性。 ```js function foo(a, b){ return a + b; } console.log(foo); ``` 如果你在瀏覽器試的話,你打開第一層會有四個屬性,分別為 **name、arguments、length、caller**。 - ***name***: function 的名稱,是一個 string。 - ***arguments***: function 的參數,但你會看到是 **null**,這是因為你沒有執行函數並且沒有傳參數給它,一旦你執行了函數,**arguments** 就會變成一個類似陣列的物件,並且在函數內讀取的到。 - ***length***: function 參數的數量,是一個 number,紀錄你有多少個參數,但如果你的參數是不固定的,像是 `function bar(...args){}` 會顯示為 0。 - ***caller***: 誰執行了這個 function,你也只會看到 **null**,你可以用其他 function 呼叫該 function,然後在該 function 裡面 log `[function name].caller`,就可以回給你呼叫你的 function 資訊。 **注意**:declaration 的作法會做 function hoisting ,在另一篇 [What is hoisting?](https://hackmd.io/@FizzyElt/what-is-hoisting) 中有解釋 --- expression 會有兩種狀況,一個是匿名,另一個是具名。 [**function expression**](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/function) >A function expression is very similar to and has almost the same syntax as a function declaration (see [`function`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function) statement for details). The main difference between a function expression and a function declaration is the **_function name_**, which can be omitted in function expressions to create _anonymous_ functions. ```js const foo = function(){} // 匿名 const bar = function test(){} // 具名 ``` 差別主要在 function 屬性名稱不同,如果是匿名那 function 名稱會是變數名稱,具名的話名稱會是 function 本身的名稱,而不是變數名稱。 --- ### arrow function arrow function 只能匿名,所以只有 expression 的方式。 [arrow function expressions](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions) >An **arrow function expression** is a compact alternative to a traditional [function expression](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/function), but is limited and can't be used in all situations. 並且屬性也只剩下 **name** 跟 **length** 兩個。 ```js const foo = (a, b) => {}; console.log(foo); ``` 相比一般 function,arrow function 少了很多功能,這就是我們平常拿來比較差異的地方。 >- Arrow functions don't have their own bindings to [`this`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this), [`arguments`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/arguments) or [`super`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/super), and should not be used as [methods](https://developer.mozilla.org/en-US/docs/Glossary/Method). >- Arrow functions don't have access to the [`new.target`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/new.target) keyword. >- Arrow functions aren't suitable for [`call`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/call), [`apply`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/apply) and [`bind`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind) methods, which generally rely on establishing a [scope](https://developer.mozilla.org/en-US/docs/Glossary/Scope). > - Arrow functions cannot be used as [constructors](https://developer.mozilla.org/en-US/docs/Glossary/Constructor). > - Arrow functions cannot use [`yield`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/yield), within its body. 關於 `this` 的問題在網路上有很多解說,所以不多作贅述,這裡比較可以單獨拿來討論得是 `call`、`apply`、`bind` 這三個方法,因為沒有綁定 `this` 那還能用嗎? 答案是可以的,只是你傳入的任何 `thisArg` 都不會有任何作用。 ```js const foo = () => { console.log(this); } foo.call({ value: 20}); // global this foo.apply({ value: 20}); // global this foo.bind({ value: 20}); foo(); // global this ``` 關於 arrow function 如何捕捉 `this` 可以參考[這裡](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions#arrow_functions_used_as_methods),裡面基本涵蓋了開發的各種狀況。 ### 怎麼選擇 如果你單純都是用 function 基本功能,arrow function 就可以應付大部分狀況,我的習慣是如果是一個較複雜的 function 我會用一般的 function,如果要傳入 callback ,或是一些簡單的計算我會用 arrow function,不過你很清楚之間的差異的話其實怎麼用都是看個人習慣。 ```js function foo(){ //... } [].map((v) => v); ```