JavaScript 原型和原型鏈

·

2 min read

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

Overview

範圍

  • 如何準確判斷一個變量是不是陣列

  • class 的原型本質

知識點

涵蓋以下三大點

  • class 實現繼承

  • instanceOf 使用

  • 原型和原型鏈

class

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

  • constructor

  • 屬性

  • 方法

// 類
// 注意使用以大寫字母
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

  • 擴展重寫方法

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 的父類

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

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

原型:隱式原型和顯式原型

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

原型鏈

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)