# Arrow Function 箭頭函式 & 內部的 this
Arrow function expression 可以說是原型function expression的一個簡潔寫法的替代方案,但是在使用上有一些限制和語法上的不同。
* 箭頭函式不具備自己的'this', 'arguments' 或 'super' 綁定,而且不適合用作於物件的方法
* 箭頭函式不可以使用 Constructors,如果使用 new 方法呼叫他們,會拋出 TypeError 的錯誤。
* 箭頭函式無法在主體內使用 "yield",並且也無法使用 generator function。
## 箭頭函式的基本語法
const sum = function(a,b) => a + b
## 不具備自己的 'this', 'arguments' 或 'super' 綁定
```javascript=
// 箭頭函式的基本語法
const sum = function(a,b) => a + b
// 不具備自己的 this 綁定
const obj = {
value: 10
getValue: () => {
// 在箭頭函式內的 this 會指向外部的作用域,而不是 obj
return this.value
}
}
console.log(obj.getValue())
// 在這裡 this.value 會是 undefined,因為箭頭函式內並沒有自己的this 綁定
```
```javascript=
// 不具備自己的 arguments 綁定
const printArguments = () => {
// 箭頭函式內的 arguments 會參考到作用域外部的 arguements
// 而不是函數自己的 arguments
console.log(arguments)
}
// 此處會得到 Uncaught ReferenceError: arguments is not defined
printArguments(1,2,3)
```
```javascript=
// 不具備自己的 super 綁定
class Parent{
constructor(){
this.name = "Parent"
}
printName = () => {
// 箭頭函數內部沒有自己的 super綁定,所以無法使用 super
console.log(this.name)
}
}
const child = new Parent()
child.printName()
// 箭頭函式內的 this 就會指向外部作用域的 this,會正確印出 "Parent"
```
[MDN super的用法](https://developer.mozilla.org/zh-TW/docs/Web/JavaScript/Reference/Operators/super)
## 異步函數內使用的箭頭函式
**使用一般函式和箭頭函式方法的比對**
**一般函式的用法:** 這裡的 function 會綁定自己的 this,當這些函數被作為回乎傳遞給 fetch 的 "then" 方法時,可能會不正確,因為它會取決於被呼叫的上下文。
**箭頭函式的用法:** 不具備自己的 "this" 綁定,而是繼承外部作用域的 "this",在這裡就會是跟 fetchData 函數的 "this" 一致,這使得箭頭函式內部的 "this" 就會自然而然地保留外部作用域的 "this",而不會受到 **.then 方法內部的綁定問題**的影響。
```javascript=
// 一般函式
function fetchData(){
fetch('https://api.example.com/data')
.then(function(response){
// 這裡的 this 可能會有問題,因為是來自於 fetch 回呼函式產生的,這裡的 function 會綁定自己的 this。
return(response.json())
})
.then(function(data){
// 同樣的問題也會發生在這裡
console.log(data)
})
}
// 箭頭函式的用法
function fetchData(){
fetch('https://api.example.com/data')
.then(response => response.json())
.then(data => console.log(data))
}
```
## 重新認識 "this" & 箭頭函式內部的 "this" 用法
this 是 object 正在執行 function 的一個參考值
1. method -> obj
如果 function 是一個物件的方法,那 "this" 指向的就是 obj
2. function -> global (window, global)
```javascript=
const video = {
titel: "a",
play(){
console.log(this)
}
}
video.stop = function(){
console.log(this)
}
video.play()
video.stop()
function playVideo(){
console.log(this)
}
// normal function 印出來就會是 WINDOW OBJECT
playVideo()
// constructor function
function Video(title){
this.title = title
console.log(this)
}
const v = new Video("b") // 在這裡 new 會 create 一個空物件 {},並將 title 帶入。
```
video.play() 和 video.stop() 都會指向 video obj

若是普通的function: playVideo 函式印出來的 this,就會是 window object。

constructor function Video 印出來的 this

function 內部不同的 this 指向問題:
```javascript=
const video = {
title: "a",
tags: ["a", "b", "c"],
showTags(){
// 在 showTags method 裡指向 video obj ,抓取 tags 屬性的值,使用 forEach 方法。
// forEach 方法若如下使用普通 function,會有自己的this,在這裡就會顯示錯誤,因為這裡 this 指向的就是 window object。
this.tags.forEach(function(tag){
console.log(this.title, tag)
})
}
}
// 這裡解決 forEach 內部 console.log 出現 undefined 的問題其中兩個方式:
// 1. 加入 forEach 的第二個參數 thisArg
forEach(callbackFn, thisArg)
// 在 showTags 方法內部,可以在 forEach 的第二個參數放入 "this"
this.tags.forEach(function(tag){
console.log(this.title, tag)
}, this)
// 2. 直接改成箭頭函式: 直接抓取外部作用域的 "this",也就是 video 的 obj
this.tags.forEach((tag) => console.log(this.title, tag))
```
使用一般函式內部印出來的 this.title 產生的問題,小心就會變成 undefined 錯誤

## 參考資料
* [MDN Arrow Function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions)
* [JavaScript this Keyword](https://www.youtube.com/watch?v=gvicrj31JOM)