---
# System prepended metadata

title: What advantage is there for using the arrow syntax for a method in a constructor?

---

# What advantage is there for using the arrow syntax for a method in a constructor?
### Q:對建構式中的方法使用箭頭函式有什麼優點?

Ans:
在建構式中使用箭頭函式作為方法的主要優點是
* 一般函式的this會依照執行時被呼叫的地方決定，箭頭函式會自動綁定 (bind) this 到宣告箭頭函式當時的環境 (context)。當用此建構式創建新物件時，this的值會關聯於(指向)該物件。
* 提升程式碼的可閱讀性


```+
const Person = function (firstName) {
  this.firstName = firstName;
  this.sayName1 = function () {
    console.log(this.firstName);
  };
  this.sayName2 = () => {
    console.log(this.firstName);
  };
};

const john = new Person('John');
const dave = new Person('Dave');

john.sayName1(); // John
john.sayName2(); // John

// The regular function can have its 'this' value changed, but the arrow function cannot
john.sayName1.call(dave); // Dave (because "this" is now the dave object)
john.sayName2.call(dave); // John

john.sayName1.apply(dave); // Dave (because 'this' is now the dave object)
john.sayName2.apply(dave); // John

john.sayName1.bind(dave)(); // Dave (because 'this' is now the dave object)
john.sayName2.bind(dave)(); // John

var sayNameFromWindow1 = john.sayName1;
sayNameFromWindow1(); // undefined (because 'this' is now the window object)

var sayNameFromWindow2 = john.sayName2;
sayNameFromWindow2(); // John

```

## Arrow Functions 的 this 判斷原則
> MDN & W3Schools:
> (1) In arrow functions, this retains the value of the enclosing lexical context's this.
> (2) Arrow functions do not have their own this.
> (3) In global code, it will be set to the global object.

Arrow Functions 的 this 和傳統函數this的一個重大差異就是在語彙環境(lexical context)。
「語彙環境」，也就是程式碼的實際位置（全域或是函式內）/ 函式被宣告時所在的 scope。



* 傳統函數每次呼叫函數，都會建立一個新的函數執行環境 (Function Execution Context)，然後建立一個新的 this 引用物件，指向當下的呼叫者。

![](https://i.imgur.com/voIwg0J.png)

* Arrow Functions 沒有 prototype (原型)，所以箭頭函式本身不會有自己的 this 引用物件，呼叫 this 時，會沿用語彙環境外圍的 this。

* 箭頭函式的this在定義的時候繼承自外層第一個普通函式的this，若外層沒有普通函式，則this指向Global Context的Global 物件。

* 箭頭函式本身的this指向不能改變，但可以修改它要繼承的物件的this

* 由於箭頭函式看的是語彙位置，往外一層是 Global Context，不管在一般模式或嚴謹模式，this 都是 Global 物件：
```+
var whatsThis = () => {
  return this;
}

console.log( whatsThis() ); // window
```


## 小試身手
```+
//01 傳統函數
var x = 10;
var obj = {
    x: 20,
    f: function(){
        console.log('Output#1: ', this.x);
        var foo = function(){ console.log('Output#2: ', this.x); }
        foo();
    }
};

obj.f();

//02 Arrow Functions I
//內部函數是 Arrow Function，外部函數仍是傳統函數：
var x = 10;
var obj = {
    x: 20,
    f: function(){
        console.log('Output#1: ', this.x);
        var foo = () => { console.log('Output#2: ', this.x); }
        foo();
    }
};

obj.f();

//03 Arrow Functions II
//外部函數是 Arrow Function，內部函數是傳統函數：
var x = 10;
var obj = {
    x: 20,
    f: () => { 
        console.log('Output#1: ', this.x);
        var foo = function() { console.log('Output#2: ', this.x); }
        foo();
    }
};

obj.f();

//04 Arrow Functions III
//外部函數和內部函數都是 Arrow Function：

var x = 10;
var obj = {
    x: 20,
    f: () => { 
        console.log('Output#1: ', this.x);
        var foo = () => { console.log('Output#2: ', this.x); } 
        foo();
    }
};

obj.f();
```

```+
//解答
//(1)
Output#1:  20
Output#2:  10
//(2)
Output#1:  20
Output#2:  20
//(3)
Output#1:  10
Output#2:  10
//(4)
Output#1:  10
Output#2:  10
```
## 不可使用箭頭函式的情況
* **物件中的方法**
箭頭函式會以定義當下的this值為this值=window物件，所以是存取不到物件中的this.array值的。
```+
const calculate = {
  array: [1, 2, 3],
  sum: () => {
    return this.array.reduce((result, item) => result + item) ////this指向 window Object
  }
}

//TypeError: Cannot read property 'array' of undefined
calculate.sum()
```
* **Prototype 中使用 this**
一樣是 this 的問題，如果原型上新增一個箭頭函式，並嘗試使用 this 的話會指向全域。
```+
function MyCat(name) {
    this.catName = name;
}

MyCat.prototype.sayCatName = () => {
    return this.catName;  //this指向 window Object
};

MyCat.prototype.sayCatName2 = function () {
    return this.catName;
};

cat = new MyCat("Mew");

console.log(cat.sayCatName()); //undefined
console.log(cat.sayCatName2()); //Mew
```
* **DOM 事件監聽**
```+
const button = document.getElementById('myButton')

button.addEventListener('click', () => {
  this.innerHTML = 'Clicked button'  //this指向 window Object
})
//TypeError: Cannot set property 'innerHTML' of undefined
```
* **建構式**
由於 this 是在物件下建立，所以箭頭函式不能像 function 一樣作為建構式的函式，如果嘗試使用此方法則會出現錯誤 (... is not a constructor)。
```+
const Message = (text) => {
  this.text = text;
}
// Throws "TypeError: Message is not a constructor"
const helloMessage = new Message('Hello World!');
```
## 小結
傳統函式: this值是動態的，由呼叫這個函式的擁有者物件(Owner)決定
箭頭函式: this是lexical作用域決定，也就是由週邊的作用域所決定

## 參考資料:
[mdn箭頭函式](https://developer.mozilla.org/zh-TW/docs/Web/JavaScript/Reference/Functions/Arrow_functions)
https://eyesofkids.gitbooks.io/javascript-start-from-es6/content/part4/arrow_function.html
https://something-about-js-book.onejar99.com/day21
https://wcc723.github.io/javascript/2017/12/21/javascript-es6-arrow-function/