深入了解JavaScript中基於原型(prototype)的繼承機制


原型

前言

繼承是面向對象編程中相當重要的一個概念,它對幫助代碼復用起到了很大的作用。

正文

Brendan Eich在創建JavaScript時,沒有選擇當時最流行的類繼承機制,而是借鑒Self,用到了基於原型(prototype)的繼承機制,這導致了JavaScript在繼承機制方面與Java、C++等基於類繼承機制的語言有着顯著的區別。

其具體在於—C++的多重繼承、Java的繼承和接口實現中都包含""的概念,它們傾向於在創建對象之前[1]已經規定了對象需要繼承的類和實現的接口,並且使用類與類之間的繼承方式

而在JavaScript中沒有""的概念,在對象之后所繼承的對象也是可以發生動態變化的,並且使用的是對象與對象之間的繼承方式

如果將JavaScript中由string,number,bigint,boolean,null,undefined,symbol組成的基礎類型與其對應的值都按下不表,余下的引用類型與其對應的值將都存在着__proto__[2]屬性,指向繼承的原型對象[3]

__proto__存在於每個對象中不同,prototype屬性只存在於函數中,在默認的的情況下所有對象的__proto__屬性的值與其構造函數下的prototype屬性的值是一致的。

let obj = new Object();
obj.constructor === Object;//true
//obj的__proto__屬性的值與obj的構造函數的prototype屬性的值指向同一塊堆內存
obj.__proto__ === obj.constructor.prototype;//true
obj.__proto__ === Object.prototype;//true

在這里插入圖片描述

所有函數的構造函數都指向Function:

Object.constructor === Function;//true
//Object的__proto__屬性的值與Object的構造函數的prototype屬性的值指向同一塊堆內存
Object.__proto__ === Object.constructor.prototype;//true
Object.__proto__ === Function.prototype;//true

Function.constructor === Function;//true
//Function的__proto__屬性的值與Function的構造函數的prototype屬性的值指向同一塊堆內存
Function.__proto__ === Function.constructor.prototype;//true
Function.__proto__ === Function.prototype;//true

在這里插入圖片描述

Function的prototype屬性的原型指向Object.prototype:

Object.prototype === Function.prototype.__proto__;//true

在這里插入圖片描述

不單單是 Function 的prototype屬性的原型指向 Object.prototype ,幾乎所有的函數[4]的prototype屬性的原型指向 Object.prototype ,從V8的測試代碼中可見一斑:
在這里插入圖片描述
最后,位於原型頂點的是Object.prototype.__proto__,它指向 null:

Object.prototype.__proto__ === null;//true
Object.prototype.constructor === Object;//true

在這里插入圖片描述

根據以上邏輯畫的原型指向圖:
效果圖
為了加深理解,我將再定義一個構造函數:

function Person(){
	
}
Person.constructor === Function;//true
Person.__proto__ === Person.constructor.prototype;//true
Person.__proto__ === Function.prototype;//true

在這里插入圖片描述
通過新定義的構造函數創建對象:

let person = new Person();
person.constructor === Person;//true
person.__proto__ === person.constructor.prototype;//true
person.__proto__ === Person.prototype;//true

在這里插入圖片描述
根據以上邏輯畫的最終的原型指向圖:

在這里插入圖片描述

結尾

了解JavaScript中基於原型(prototype)的繼承機制的重點在於捋清楚Object與Function的__proto__、constructor、prototype屬性的指向關系,再進一步了解Object和Function各自對應的值以及通過Function對應的值創建出來的對象的__proto__、constructor、prototype屬性的指向關系,就大功告成了。
聽起來可能有一點點繞,最好是動手畫一下圖,以后忘記的時候看一下自己畫的圖就又想起來了。
最后,本人才疏學淺,如有錯誤之處,還望各位不理賜教。


  1. 這里的措辭最初為程序運行之前,后聯想到hotswap,特意改為對象創建后。 ↩︎

  2. 雖然__proto__已經被不推薦使用,但是為了更直觀,我在此文中獲取對象原型的方法都將通過對象的__proto__屬性,還望悉知。 ↩︎

  3. Object.prototype繼承的原型指向null。 ↩︎

  4. bind、apply和call沒有prototype屬性。 ↩︎


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM