---
# System prepended metadata

title: Constructor 建構式
tags: [JavaScript, prototype]

---

# Constructor 建構式
###### tags: `JavaScript` `prototype`
> 也就是用來**建構物件的函式**。
> 透過函式建立物件的樣板，減少重複的程式碼。
## 前言：物件導向程式設計
>**物件導向程式設計(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。

![](https://i.imgur.com/SI0Ygfj.png)
- 【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);
```

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


### 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