# 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);
```