# JavaScript 原型和原型鏈

💡 為什麼原型和 原型鏈很重要？因為JS 本身是基於原型繼承的語言， ES6 之後可以使用 `Class` 實作繼承

# Overview

## 範圍

* 如何準確判斷一個變量是不是陣列
    
* `class` 的原型本質
    

## 知識點

涵蓋以下三大點

* `class` 實現繼承
    
* `instanceOf` 使用
    
* 原型和原型鏈
    

# class

class 本身像是模板的作用，可以在 constructor 內對屬性定義賦值，透過 class 可以聲明 new 實例

* constructor
    
* 屬性
    
* 方法
    

```jsx
// 類
// 注意使用以大寫字母
class IDOL {
  constructor(name, age) {
    // this 為當前構建的實例
    this.name = name;
    this.age = age;
  }
  sayHi() {
    console.log(`姓名 ${this.name} ，年紀 ${this.age}`);
  }
}

// 通過類聲明 對象/實例
const jimin = new IDOL('Park Mochi', 28);
console.log(jimin.name);
console.log(jimin.number);
jimin.sayHi();

// Park Mochi
// 28
// 姓名 Park Mochi ，年紀 28
```

# 繼承

主要透過以下三點方法，細節請看程式碼

* extends
    
* super
    
* 擴展重寫方法
    

```jsx
class Animal {
  constructor(name) {
    this.name = name;
  }
  eat() {
    console.log(`${this.name} is eating something`);
  }
}

class Cat extends Animal {
  constructor(name, color) {
		// 不需要再寫一次 this.name = name
    // super 會將 name 給 People constructor 處理
    super(name);
    this.color = color;
  }
  look() {
    console.log(`${this.name} 看起來是 ${this.color}`);
  }
}

class Dog extends Animal {
  constructor(name, job) {
    super(name);
    this.job = job;
  }
  work() {
    console.log(`${this.name} 的工作是 ${this.job}`);
  }
}

const benzCat = new Cat('二哈賓', 'black and white');
console.log(benzCat.name);
console.log(benzCat.color);
benzCat.look();

const searchDog = new Dog('Nero', 'searching berried people');
console.log(searchDog.name);
console.log(searchDog.job);
searchDog.work();

// 二哈賓
// black and white
// 二哈賓 看起來是 black and white
// Nero
// searching berried people
// Nero 的工作是 searching berried people
```

### 類型判斷 `instanceof` 可以判斷變量是否來自構建 class 的父類

```jsx
benzCat instanceof Cat // true
benzCat instanceof Animal // true
benzCat instanceof Object // ture

[] instanceof Array // true
[] instanceof Object // true
{} instanceof Object // true
```

## **原型：**隱式原型和顯式原型

```jsx
// class 實際上是函數，可見是語法糖
typeof Animal // 'function'
typeof Cat // 'function'

// 隱式原型和顯示原型
console.log(benzCat.__proto__)  
console.log(Cat.prototype)
console.log(benzCat.__proto__ === Cat.prototype) // true 引用為同一個原型
```

* 每個 `class` 都有顯式原型 `prototype`
    
* 每個實例都有隱式原型 `__proto__`
    
* 實例的`__proto__` 指向對應 class 的 prototype
    

## **原型鏈**

```jsx
console.log(Cat.prototype.__proto__)
console.log(Animal.prototype)
console.log(Animal.prototype === Cat.prototype.__proto__)
```

> 會先在自身中尋找方法或屬性，如果找不到，才向上一層利用隱式原型 `__proto__` 去找，直到找到最上層指向 Object，而 Object.**proto** 永遠指向 null

## instanceof 原理

判斷 `instanceof` 為真主要是透過實例 \_\_**proto\_\_** 能不能找到 class 的顯式原型 (prototype)
