點燈坊

失くすものさえない今が強くなるチャンスよ

深入探討 __proto__、prototype 與 [[prototype]]

Sam Xiao's Avatar 2021-01-02

Object 有 3 個非常像的 Property:__proto__prototype[[prototype]],徹底了解有助於我們看清 Prototype 本質。

Version

ECMAScript 2015

Class

class Book {
  constructor(title, price) {
    this.title = title
    this.price = price
  }

  showDescription() {
    return `${this.title} / ${this.price}`
  }
}

let book = new Book('FP in JavaScript', 100)
book.showDescription() // ?

這是 ES6 的 class,包含 titleprice property 與 showDescription() method。

prototype006

Constructor Function

let Book = function(title, price) {
  this.title = title
  this.price = price
}

Book.prototype.showDescription = function() {
  return `${this.title} / ${this.price}`
}

let book = new Book('FP in JavaScript', 100)
book.showDescription() // ?

Class 其實是 constructor function 的 syntatic sugar,showDescription() 會定義在 Book.prototype

prototype002

目前為止 book.__proto__ 指向 Book.prototype,因此我們能透過 Book.prototype 去新增 method,等效於對 book.__proto__ 新增 method。

prototype007

prototype

prototype000

Q:我明明只定義 Book(),為什麼橫空出世有了 Book.prototype 呢 ?

當 function 建立時,無論是 constructor function 或一般 function,由於 function 也是 Object,因此自帶 prototype property 指向 Object,而該 Object 的 prototype 正是來自於 Object.prototype

prototype001

_proto_

Q:為什麼有了 prototype,又有了 __proto__ ?

先澄清一個觀念,prototype 為 function 專屬 property;而 __proto__ 為 Object 專屬 property,但因為 function 也是 Object,所以 function 同時有 prototype__proto__

__proto__ 指向 Object 的 prototype,如 bookBook.prototype 都是 Object,因此其 __proto__ 都不約而同的指向 Object.prototype

prototype003

Book() 的 prototype 呢?可發現 Book() 的 prototype 是 Function.prototype,而 Function.prototype 的 prototype 是 Object.prototype

prototype004

[[prototype]]

至於 [[prototype]] 呢 ? 根據 ECMAScript 規格,[[prototype]] 屬於 internal property,過去外界只能透過 Object.getPrototypeOf()Object.setPrototypeOf() 去取得 [[prototype]] property,但 ES6 定義了 __proto__ 之後,外界可直接透過 __proto__ 存取 [[prototype]],也就是目前 __proto__[[prototype]] 意義相同,都是指向 Object 的 prototype。

prototype005

Conclusion

  • 其實 prototype 觀念並不難,只是 ECMAScript 同時有 prototype property,又有 prototype object,且 function 又有 Object 特性,才導致 prototype 觀念混在一起
  • Function 的 prototype property 並不是指向其 prototype Object,__proto__ property 才是
  • Function 的 prototype property 只有在當其搭配 new 成為 constructor function 時才有意義,prototype property 所指向的 Object 會成為新 Object 的 prototype Object

Reference

許國政, 008 天重新認識 JavaScript
Peter Chang, JavaScript 必須知道的繼承 prototype
Dmitry Soshnikov, JavaScript. The Core.
Kenneth Kin Lum, JavaScript’s Pseudo Classical Inheritance Diagram
Dr.Axel Rauschmayer, Objects and Inheritance