原型、原型鏈、原型繼承

簡介

  • 原型是 JavaScript 中實現物件間繼承和方法共享的基礎機制
  • 允許物件訪問並使用不屬於它們自身,而是定義在它們原型上的屬性和方法
  • 每個物件有一個內部隱藏屬性:[[Prototype]],無法直接訪問
  • 訪問原型的方法:
    • __proto__
    • Object.getPrototypeOf()
note-img

原型鏈(Prototype Chain)

  • 在物件實例和類別中設定連結(原型鏈)
  • 如果訪問某個屬性,但在物件中沒有時,會在原型(prototype)中尋找
  • 若沒有找到,會再從原型中的原型繼續找
  • 直到找到,或是找到最上層的終點(null)為止
  • 這條連續的路徑,被稱為原型鏈
class Phone {  call() {    console.log('call me maybe')  }}const myPhone = new Phone()// 從原型鏈中,找到call方法myPhone.call() // call me maybe// 找到myPhone的原型Phone => 原型Object => Object的原型(終點是null)console.log(myPhone.__proto__.__proto__.__proto__) // null

查看物件的原型

  • Object.getPrototypeOf
class Phone {  call() {    console.log('call me maybe')  }}const myPhone = new Phone()console.log(Object.getPrototypeOf(myPhone)) ⬇️
note-img

檢查某個屬性是否是該物件自己本身的,而非原型內的

  • hasOwnProperty
class Person {  constructor(name) {    this.name = name  }}Person.prototype.age = 30const jude = new Person('Jude')console.log(jude.hasOwnProperty('name')) // true,因為 'name' 是 jude 物件自身的屬性console.log(jude.hasOwnProperty('age')) // false,因為 'age' 是通過原型繼承的屬性

原型繼承(Prototype Inheritance)

  • 如果在不同物件中,都用到相同的方法
  • 最簡單的方式是在每個物件都寫一次一樣的函式
  • 但缺點是,要修改或擴充時,非常不方便
  • 如果有 100 個物件都有相同的walk,就佔了 100 個記憶體空間,造成效能浪費

範例

const me = {  walk() {    return 'walking'  }}const he = {  walk() {    return 'walking'  }}

改善方式

  • 可以創建一個Person的 class
  • 基於Person建立其他物件,共享Person的屬性或方法
  • 當要變更時,只要去修改Person的 prototype,就可以一併修改實例所繼承的方法
class Person {  walk() {    return 'walking'  }}const me = new Person()const he = new Person()console.log(me.walk()) // walkingconsole.log(he.walk()) // walkingPerson.prototype.walk = function () {  console.log('new walking')}console.log(me.walk()) // new walkingconsole.log(he.walk()) // new walking

常用內建構造函式

  • 創建以下類型時,因為原型繼承,可以使用該種類的方法
  1. Object
  2. Array
  3. String
  4. Number
  5. Date
const myArray = [1, 2, 3]// 使用 Array 的原型方法// push 方法是從 Array.prototype 繼承而來的myArray.push(4)console.log(myArray) // [1, 2, 3, 4]const myString = 'Hello'// 使用 String 的原型方法// toUpperCase 方法是從 String.prototype 繼承而來的const uppercaseString = myString.toUpperCase()console.log(uppercaseString) // HELLO

參考資料

# JavaScript # Prototype