---
# System prepended metadata

title: function and arrow function
tags: [note, Javascript]

---

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