# Constructor 建構式
> 也就是用來**建構物件的函式**。
> 透過函式建立物件的樣板,減少重複的程式碼。
## 前言:物件導向程式設計
>**物件導向程式設計(Object-oriented programming,OOP)**
每一個物件都能夠接受資料、處理資料並將資料傳達給其它物件,與傳統(直接對電腦下指令)的思想剛好相反,加強程式的靈活性和可維護性,並且在大型專案設計中廣為應用。
- 以 `類別` 為基礎 (class-based) 的物件導向。
- 以 `原型` 為基礎 (prototype-based) 的物件導向。
>前者有C++、Java、Python,而Javascript是屬於後者。
## 為什麼需要建構式?
- 程式碼重複性降低
- 易於維護與擴充
- 節省記憶體空間
```+
//典型建構式寫法
function Person (firstName,lastName){
this.firstName = firstName;
this.lastName = lastName;
}
let john = new Person("John","Wu");
let Amy = new Person("Amy","Lin");
let Kiki = new Person("Kiki","Hello");
console.log(john);
```
### new 關鍵字
- 是運算子(operators)的一種。
- 只能由function建立。
- 【1】建立一個新的空白物件。
- 【2】將Person函式裡面的屬性名稱和屬性值設為原型。
- 【3】執行Person函式,將this綁定到新物件上。(這個過程稱為實體化)

#### new有害說與物件實體化
>JavaScript長期以來就有反對使用new運算符用於實體化物件的言論,主要的理由是語言本身設計上的缺陷。
- 容易與一般函式混用時造成混亂(通常第一個字首會大寫,但還是不易區分)。
- 如果沒有使用new來實體化物件,程式不會報錯,但會導向不同的結果。
- 執行函式也有可能會隱藏對於物件實體的複雜的生成過程。
```+
//防止錯誤的範例寫法
function Player(name, age)
{
if (this instanceof Player){
this.name = name
this.age = age
}else{
return new Player(name, age)
}
}
const aPlayer = Player('Inori', 16)
const bPlayer = new Player('Gi', 16)
```
### ES5 Object.create
- 更直觀使用物件原型(prototypal inheritance)的方式。
- 真的很舊的瀏覽器可能會無法使用(需改寫成polyfill的形式)。
- 物件變更屬性設定更自由。
```+
let Person = {
firstName: 'Default',
lastName: 'Default',
getFullName: function () {
return this.firstName + " " + this.lastName;
}
}
let john = Object.create(Person);
console.log(john);
console.log(john.firstName);
//輸出的結果會得到一個空物件,但是繼承了Person的屬性和方法。
john.firstName="wu" //原型鏈會尋找最外層的屬性
console.log(john.firstName);
```

### ES6 類別定義
>在其他的語言,類別是創建物件的藍圖,但在JS,類別本身是被建立出來的物件。
- 骨子裡仍然是以原型為基礎的物件導向!(並非以類別為基礎)
- 提供更簡潔的語法來作物件建立與繼承。
- 讓熟悉以類別為基礎的物件導向程式語言的開發者使用。
```+
class Person {
constructor(firstName,lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
getFullName: function () {
return this.firstName + " " + this.lastName;
}
}
const john = new Person('John',"Wu");
```
#### 再來看看繼承怎麼寫:
```javascript=
function Person(name) {
this.name = name;
const state = 'Taiwan';
this.getFrom = () => `${this.name} from ${state}.`;
}
//傳統建構式繼承
function Employee(name, position) {
// 將 this 送給 Person 建立 properties
Person.call(this, name);
this.position = position;
// public properties
this.getPosition = () => `${this.name}'s position is a ${this.position}.`;
}
const luck = new Employee('Luck', 'Front-end');
console.log(luck.getFrom()); // Luck from Taiwan.
console.log(luck.getPosition()); // Luck's position is the Front-end.
--------------------------------------------------------------------------
//ES6 Class繼承
class Employee extends Person {
constructor(name, position) {
// 用 super 呼叫 extends 指定的 class
super(name);
this.position = position;
}
getPosition() {
return `${this.name}'s position is a ${this.position}.`;
}
}
const luck = new Employee('Luck', 'Front-end');
console.log(luck.getFrom()); // Luck from Taiwan.
console.log(luck.getPosition()); // Luck's position is the Front-end.
```
### 練習題目
```+
function Person(name) {
this.name = name;
}
var person = Person('John');
console.log(person); // undefined
console.log(person.name);
// Uncaught TypeError: Cannot read property 'name' of undefined
var person = new Person('John');
console.log(person); // Person { name: "John" }
console.log(person.name); // "john"
```
## 參考資料
https://www.youtube.com/watch?v=xSu7TbPPy34&ab_channel=%E5%BD%AD%E5%BD%AD%E7%9A%84%E8%AA%B2%E7%A8%8B
https://wcc723.github.io/javascript/2017/12/18/javascript-constructor/#%E5%BB%BA%E6%A7%8B%E5%BC%8F
https://eyesofkids.gitbooks.io/javascript-start-from-es6/content/part4/prototype.html
https://medium.com/enjoy-life-enjoy-coding/javascript-es6-%E4%B8%AD%E6%9C%80%E5%AE%B9%E6%98%93%E8%AA%A4%E6%9C%83%E7%9A%84%E8%AA%9E%E6%B3%95%E7%B3%96-class-%E5%9F%BA%E6%9C%AC%E7%94%A8%E6%B3%95-23e4a4a5e8ed