---
# System prepended metadata

title: 甚麼是箭頭函式與箭頭函式this的指向差異
tags: [JavaScript, 學習, 箭頭函式]

---

###### tags: `JavaScript` `箭頭函式` `學習` 
{%hackmd BJrTq20hE %}
# 甚麼是箭頭函式與箭頭函式this的指向差異
## 1-1甚麼是箭頭函式?
箭頭函式是一種新的函是寫法，與一般函式的寫法不同，有可以縮寫的優點。
範例如下
### 1-1-1一般函式
```javascript=
let arr = [1,2,3,4,5];
let newarr = arr.map(function(item){
  return  item*2
});
console.log(newarr);//[2,4,6,8,10]
```
### 1-1-2箭頭函式
```javascript=
let arr = [1,2,3,4,5];
let newarr = arr.map((item)=>{
  return  item*2
});
console.log(newarr);//[2,4,6,8,10]
```
可以發現把function移除，然後在()後加上=>

## 2-1箭頭函式的縮寫

如果函式的參數只有一個，參數()也可以省略。
加入沒有參數的話()或兩個含以上參數存在的話則()不可省略。
```javascript=
let arr = [1,2,3,4,5];
let newarr = arr.map(item=>{
  return  item*2
});
console.log(newarr);//[2,4,6,8,10]
```

### 2-2箭頭函式的縮寫2
函式需要return值的時候{}也可以省略，但是要注意原本{}的內容要寫在同一行。
```javascript=
let arr = [1,2,3,4,5];
let newarr = arr.map(item=>item*2);
console.log(newarr);//[2,4,6,8,10]
```


## 3-1箭頭函式沒有自己的this
原函式寫法this的指向
```javascript=
var name ='window';
const obj = {
    name:'Jack',
    callMyName (){
        console.log(this.name+' this指向obj');
        // 因為在callback function 內的this都指向全域。
        setTimeout(function(){
            console.log(this.name+' this指向window')
        })
    },
}
obj.callMyName();//Jack this指向obj  window this指向window
```
從上面的例子可以看到callMyName()是從obj內調用的所以this指向obj，而setTimeout這個callback function是一種simple call 可以想成setTimeout()是放在window裡所以setTimeout()的this會指向window。

### 3-1-1 箭頭函式this的指向
```javascript=
var name ='window';
const obj = {
    name:'Jack',
    callMyName (){
        console.log(this.name+'1');
        setTimeout(()=>{
            console.log(this.name+'2')
        })
    },
    
}
obj.callMyName();//Jack1  Jack2
```
把setTimeout內的函是改寫為箭頭函式，因為箭頭函式沒有自己的this，所以在箭頭含式內的this會指向外層函式的作用域的this，外層函式為傳統函式所以this的指向與如何調用函是相關。

### 3-1-3沒有外層函式的的箭頭函式的this指向全域
```javascript=
var name ='window';
const obj = {
    name:'Jack',
    callMyName: ()=>{
        console.log(this.name);
    },
    
}
obj.callMyName();//window
```
箭頭函式內的this會與外層函式的this指向相同，上面的範例中沒有外層函式，所以指向全域。

### 3-1-4外層也是箭頭函式的this的指向全域
```javascript=
var name ='window';
const obj = {
    name:'Jack',
    callMyName: ()=>{
        console.log(this.name+'1');
        setTimeout(()=>{
            console.log(this.name+'2')
        })
    },
}
obj.callMyName();//window1  window2
```
因為setTimeout外層函數也是箭頭函式，所以this的指向看外層函式，又因為外層函式是箭頭函式且沒有更外層的函式所以所有的this都指向window。

### 3-1-5確定this的指向-方法1
```javascript=
var name ='window';
const obj = {
    name:'Jack',
    callMyName (){
        let vm = this;
        setTimeout(function(){
            console.log(vm.name)
        })
    },
    
}
obj.callMyName();//Jack
```
在callback function同層宣告變數vm=this;改變this的指向

### 3-1-5確定this的指向-方法2
```javascript=
var name ='window';
const obj = {
    name:'Jack',
    callMyName (){
        setTimeout(()=>{
            console.log(this.name)
        })
    },
    
}
obj.callMyName();//Jack
```
使用箭頭函式沒有this,會與(外層函式)作用域的this指向相同的特性把setTimeout內的this指向obj。

## 4-1 一般函式與箭頭函式其餘參數的差異

一般函式的其餘參數
```javascript=
function fn() {
    console.log(arguments)
}
fn(1, 2, 3, 4) //Arguments(4) [1, 2, 3, 4,]
```

箭頭函式則是沒有其餘參數，會報錯。

```javascript=
const fn = () => {
    console.log(arguments)
}
fn(1, 2, 3, 4) // VM1730:2 Uncaught ReferenceError: arguments is not defined

```

### 4-1-1 箭頭函式的其餘參數要怎麼寫?

```javascript=
const fn = (par, ...pars) => {
    console.log(par)
    console.log('其餘參數',...pars)
    const value = Object.values(pars)
    console.log('取出其餘物件', value)
}
fn(1, 'a', 'b', 5, 6)// 1   '其餘參數'  a b 5 6
// ['a', 'b', '5', '6']
```
## 5-1 箭頭函式與call()、apply()、bind()對於this的指向

原始函式
```javascript=
var name = '123'
const obj = {
    name: 'Jack'
}
const fn1 = function(par1, par2) {
    console.log(this.name, par1, par2)
}
fn1.call(obj, 'May', 'John') // Jack May John
```
箭頭函式
可以看到使用Call但試箭頭函式內的this是指向全域，原因是箭頭函式沒有外層函數，所以會指向全域。
```javascript=
var name = '123'
const obj = {
    name: 'Jack'
}
const fn1 = (par1, par2) => {
    console.log(this.name, par1, par2)
}
fn1.call(obj, 'May', 'John') // 123 May John
```
箭頭函式與一般函式放在一起看
```javascript=
var name = '123'
const obj = {
    name: 'Jack',
    fn1: (par1, par2) => {
    console.log('fn1',this.name, par1, par2)
    },
    fn2:function(par1, par2) {
      console.log('fn2',this.name, par1, par2)
    },
    fn3:function(par1, par2) {
      setTimeout(()=>{
        console.log('fn3',this.name, par1, par2) 
      })
    },
    fn4:(par1, par2) => {
      setTimeout(()=>{
        console.log('fn4',this.name, par1, par2) 
      })
    }
}
//雖然call有定義this指向但是在箭頭函式內的this的指向還是由外層函數的this指向為主，如果沒有外層函式則指向全域。
obj.fn1.call(obj, 'May', 'John') // 123 May John
obj.fn2.call(obj, 'May', 'John') // Jack May John
obj.fn3.call(obj, 'May', 'John') // Jack May John
obj.fn4.call(obj, 'May', 'John') // 123 May John
```
[箭頭函式、call this的指向 範例](https://codepen.io/efzdamnp-the-lessful/pen/VwXQyvp?editors=0011)

## 6-1 箭頭函式沒有建構函式

簡單的來說箭頭函式沒辦法透過.prototype增加方法
一般函式
```javascript=
const List = function(name){
    this.name = name
}
const List2 = (name)=> {
    this.name = name
}
console.log(List.prototype, List2.prototype) //{constructor: ƒ} undefined

const list = new List('Jack') 
console.log(list) // List {name: 'Jack'}
const list2 = new List2('Jack') // Uncaught TypeError: List2 is not a constructor
```