JavaScript中的原型繼承原理

??? 在JavaScript當中,對象A如果要繼承對象B的屬性和方法,那么只要將對象B放到對象A的原型鏈上即可。而某個對象的原型鏈,就是由該對象開始,通過__proto__屬性連接起來的一串對象。__proto__屬性是JavaScript對象中的內部屬性,任何JavaScript對象,包括我們自己構建的對象,JavaScript的built-in對象,任何函數(在JavaScript當中,函數也是對象)都具有這個屬性。如下圖就是一個原型鏈的例子:

??? 上圖中,A,B,C分別代表3個對象,藍色箭頭串接起來的所有對象就構成了對象C的原型鏈,其中C的_proto__屬性指向B,B的__proto__屬性指向A,A的__proto__屬性可能指向更高層的對象,也可能指向null(表示A不繼承任何對象的屬性和方法)。如果我們引用了C的某個屬性或者方法,那么JavaScript就會順著C的原型鏈進行查找,即首先查找對象C本身,看所引用的屬性名或者方法名是否存在,如果存在就停止查找直接返回,如果不存在,就通過C的__proto__屬性找到原型鏈中的B對象,繼續在B對象中查找,如果B對象中找到所引用的屬性名或者方法名,那么就停止查找直接返回,如果B對象中也不存在,就通過對象B的__proto__屬性找到原型鏈中的A對象,繼續重復上述查找過程,直到找到所引用的屬性或者方法為止(同時也可能查找完對象C的整個原型鏈也沒有找到所引用的屬性或者方法,那么該屬性或者方法就是undefined的)。

因此,只要能夠成功的為某一個對象構造出我們需要的原型鏈,那么就能讓該對象繼承我們想要它繼承的方法或者屬性。而想要成功構造對象的原型鏈,就還必須理解prototype屬性,JavaScript當中已經存在的原型鏈,以及當我們創建對象時,原型鏈被構造的過程。

?

prototype屬性

  prototype屬性存在于JavaScript的任何函數當中,這個屬性指向的對象就是所謂的原型對象,在構造原型鏈時需要原型對象。

?

JavaScript當中已經存在的原型鏈

  在JavaScript當中存在Object,Function,Array,String,Boolean,Number,Date,Error,RegExp這9個built-in函數一個built-in的Math對象,通過這上述9個built-in函數我們可以創建相應的對象,同時,這9個built-in函數的prototype屬性所指向的原型對象也是built-in的。下面的圖示解釋了這幾個函數以及各自prototype屬性所指向的原型對象之間的關系。

如果此圖看不清,可點擊此處下載

  上面的圖示中,黃色方框代表built-in函數對象,深綠色方框代表built-in函數prototype屬性指向的原型對象,名字都叫xx prototype object,淺綠色方框(即Math對象)代表普通對象,藍色箭頭連接非built-in函數對象(無論是普通對象如Math,還是原型對象)的__proto__屬性,而土黃色箭頭連接函數對象的__proto__屬性。

  通過上圖可以發現,所有built-in函數對象的原型鏈最終都指向Function prototype object,所有非函數對象的原型鏈最終都指向Object prototype object,并且Function prototype object的__proto__屬性也指向Object prototype object,Object prototype object的__proto__屬性指向為null。因此,Object prototype object是所有原型鏈的頂端。因此,通過原型鏈查找規則可知,所有built-in函數對象同時繼承了Object prototype object和Function prototype object上的屬性和方法,而所有非built-in函數對象只繼承了Object prototype object上的方法。Function prototype object包含了所有函數共享的屬性和方法,而Object prototype object包含了所有對象都共享額屬性和方法。

  對于上圖中原型對象包含的constructor屬性,下文當中有解釋。

?

創建對象時,原型鏈的構造過程

在JavaScript當中創建對象有2中方式,一種是通過定義函數使用new方法來構造,另一種是使用對象字面量的方式,即:

var obj = {name: "Jim Green"
};

使用這兩種方式創建對象時,對象的原型鏈構造過程有所不同。

1 使用函數的方式構造對象

  使用函數的方式構造對象分為兩步:首先需要定義一個函數作為構造函數,然后使用new方法構造對象。接下來就來看一下這兩個步驟會發生什么。

  假設我們定義了一個函數名為F才,此時JavaScript會為我們做兩件事,第一:根據我們定義的函數創建一個函數對象,第二,設置這個函數的__proto__屬性和prototype屬性。其中__proto__屬性指向built-in的Function prototype object,而prototype屬性指向一個為函數對象F新創建的原型對象,這個新創建的原型對象通過調用new Object()構造出來,并且為這個新創建的對象添加constructor屬性,該屬性指向函數對象F。最后的結果如下圖所示:

?

  上圖中為了方便,沒有畫出Function prototype object和Object prototype object的constructor屬性。而F prototype object的__proto__屬性為何指向Object prototype object,下文介紹new操作符時有解釋。

?

當我們使用new方法調用F函數的時候,JavaScript也會為我們做兩件事,第一,分配內存作為新創建的對象,第二,將新創建的對象的__proto__屬性指向函數F的原型對象,結果如下圖:

上圖中,obj就是調用new方法通過函數F創建出來的對象,我們可以看到對象obj的原型鏈包含了函數F的原型對象,以及Object prototype object,這樣,對象obj通過原型鏈查找規則,就能繼承函數F的原型對象,以及Object prototype object上面定義的屬性和方法了。并且如果我們想知道一個對象是由哪個方法構建的,只需要訪問這個對象的constructor屬性即可,上例中,只要我們訪問obj.constructor,那么就知道obj是由函數F創建的。同時,由于F prototype object上文中介紹是由new Object函數創建的,根據此處介紹,F prototype object的__proto__屬性應該指向Object函數的原型對象,即Object prototype object。

2 使用對象字面量定義對象

當使用對象字面量創建對象時,JavaScript會為我們做兩件事:

1 分配內存作為新創建的對象

2 將新創建對象的__proto__屬性指向Object prototype object

結果如下圖所示:

?

上圖為了簡化,同樣沒有畫出Object prototype object的constructor屬性

?

繼承

  理解了上面所講的原理之后,假設目前有一個對象A(這個對象可以是任意的,包括JavaScript built-in的對象,任何函數對象,任何原型對象,以及我們自己new出來的對象),現在想創建一個對象obj,讓obj繼承A的屬性和方法。通過上面的介紹,我們知道創建對象有兩種方式,但是使用對象字面量創建的對象其原型鏈總是只包含兩個對象,一個是其自己,一個是Object prototype object,根本不可能包含對象A,無法達到讓對象obj繼承對象A屬性和方法的效果。因此,只能使用函數的方式創建對象,讓對象A包含在新創建對象obj的原型鏈中即可。根據上面的講解,如果是用函數的方式創建對象,那么在調用new方法時,新創建對象的__proto__屬性會指向函數的原型對象。因此,只要在調用函數之前,將函數的原型對象換成A,然后再調用new方法,就可以將對象A包含在新創建的對象obj的原型鏈中,這樣通過原型鏈查找規則,obj就繼承了A的屬性和方法。假設用來創建對象obj的函數為B,則相關代碼為:

B.prototype = A;
B.prototype.constructor = B;
var obj = new B(傳入的參數)

上面代碼中的B.prototype.constructor = B,是因為對象A中可能沒有constructor屬性,或者constructor屬性不指向B,而為了方便通過訪問任何由B函數創建的對象的constructor屬性,就可以正確的知道該對象是使用函數B構造出來的。相關圖示如下圖:

上圖中虛線框所包圍的B prototype object就是定義函數B時,JavaScript為函數B生成的原型對象,但是該對象被我們用代碼替換成了對象A。由于這個被替換的B prototype object沒有其他地方再用到,因此會被回收掉。

?

參考資料:

?EcmaScript Language Specification 5

?

轉載于:https://www.cnblogs.com/chaoguo1234/p/5023929.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/458604.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/458604.shtml
英文地址,請注明出處:http://en.pswp.cn/news/458604.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

XMPP

XMPP不支持視頻聊天 支持文字聊天 但對于圖片和語音聊天支持的不好 那么就將他們轉成NSData的形式 IM Instance Message 即時聊天 聊天系統中 XMPP主要做兩個人的聊天和群聊,只用了這兩個功能 還有一個HTTP的服務器 ,他是一個旁路服務器 XMPP底層…

QT 調試

QT調試(參考下面的說明就可以正常調試):http://blog.csdn.net/wchengshen/article/details/50254731http://blog.csdn.net/sx341125/article/details/53606534 QT調用DLL: Qt中調用VS編譯dll的方法(一)----顯式調用 qt使用動態庫(…

建模元件有哪些在MapleSim中

信號庫:包含通用信號模塊、布爾、控制器、離散信號模塊、信號源、線性信號模塊、非線性信號模塊、時間離散信號模塊、查詢表、信號轉換器、數學運算、關系元件、特殊信號模塊,應用案例。 電子庫:包含電阻、運算放大器、二極管、步進電機、模擬…

iOS小筆記

controller:連接二者的橋梁;cocoa frameworks 有兩個框架:foundationfoundation 是cocoa中最基本的一些類;再mac應用程序中負責對象管理,內存管理,容器等相關數據;uikit:uikit&…

【C++】VS2010將寫好的程序打包成安裝文件發布

參考鏈接:http://blog.csdn.net/yongh701/article/details/51326142 我們可以將自己寫好的VS2010程序打包成安裝文件,給用戶安裝,具體步驟如下: 1、如下圖,同樣是新建一個項目,但是這次是新建一個其它項目…

01_jeecms建站

一、環境安裝 JDK5TOMCAT5.5MYSQL5及以上http://www.jeecms.com/tutorial/index.jhtml參考環境安裝篇二、解壓文件安裝包jeecms-v5zip,如圖圖1ROOT文件夾復制放到tomcat下的webapps文件夾(注:請先刪除webapps下原有的默認ROOT文件夾)如不想部…

WiFi基本知識

轉自:http://blog.csdn.net/myarrow/article/details/7930131 1. IE802.11簡介 標準號IEEE 802.11bIEEE 802.11aIEEE 802.11gIEEE 802.11n標準發布時間1999年9月1999年9月2003年6月2009年9月工作頻率范圍2.4-2.4835GHz 5.150-5.350GHz5.475&a…

iOS各種小理論知識

Objective-C 部分 1. 你如何理解 OC 的內存管理 OC 內存管理是基于引用計數。誰想使用某個對象 B,就要把對象 B 的計數器1,如果不 使用這個對象了,那么就把對象 B 計數器-1,如果 B 對象計數器減到 0,那么 B 對象自動會調用自己的 dealloc 函數,也就是這個對象被銷毀。 一…

libev 宏展開

想看源碼,宏太多,看著累,宏展開,再看,功力時間不夠,先放下 放上宏展開后的代碼。 libev4.20 展開方示為 ./configure 修改makefile文件,字符串 替換CC為 CPP 注意要把基礎的CC定義保留 make mv …

FreeRTOS高級篇7---FreeRTOS內存管理分析

原文:http://blog.csdn.net/zhzht19861011/article/details/51606068 內存管理對應用程序和操作系統來說都非常重要。現在很多的程序漏洞和運行崩潰都和內存分配使用錯誤有關。 FreeRTOS操作系統將內核與內存管理分開實現,操作系統內核僅規定了必要的內…

筆試題

1.是不是一個父類寫了一個virtual 函數,如果子類覆蓋它的函數不加virtual ,也能實現多態? virtual修飾符會被隱形繼承的。private 也被集成,只事派生類沒有訪問權限而已。virtual可加可不加。子類的空間里有父類的所有變量(static除外)。同一個函數只存…

FreeRTOS學習筆記——互斥型信號量

來自:http://blog.csdn.net/xukai871105/article/details/43456985 0.前言 在嵌入式操作系統中互斥型信號量是任務間資源保護的重要手段。下面結合一個具體例子說明FreeRTOS中的互斥型信號量如何使用。 【相關博文】 【FreeRTOS STM32移植筆記】 【FreeRTOS學習筆記…

JSP動態網站環境搭建應用中的詳細步驟(Tomcat和Apache/IIS的整合)

鏈接地址:http://www.cnblogs.com/dartagnan/archive/2011/03/25/2003426.html JSP動態網站環境搭建應用中的詳細步驟(Tomcat和Apache/IIS的整合)sun推出的JSP(Java Server Pages)是一種執行于服務器端的動態網頁開發技術,它基于J…

關于JS獲取select值的兩種實現方法

前幾天發了一篇關于javascript獲取select值的方法&#xff0c;后來發現有另一種實現方法&#xff0c;所以就都發出來比較一下&#xff1a; 方法一&#xff1a;通過獲取option標簽的value值來確定&#xff1a; <!DOCTYPE html> <html> <head><meta charset…

c語言題庫1

1. 用預處理指令#define 聲明一個常數&#xff0c;用以表明1年中有多少秒&#xff08;忽略閏年問題&#xff09; #define time (365*24*60*60) #define SECONDS_PER_YEAR (60 * 60 * 24 * 365) 2. 寫一個“標準”宏MIN&#xff0c;這個宏輸入兩個參數并返回較小的一個。 #di…

FreeRTOS系列第19篇---FreeRTOS信號量

來自&#xff1a;http://blog.csdn.net/zhzht19861011/article/details/50835613 本文介紹信號量的基礎知識&#xff0c;詳細源碼分析見《FreeRTOS高級篇6---FreeRTOS信號量分析》 1.信號量簡介 FreeRTOS的信號量包括二進制信號量、計數信號量、互斥信號量&#xff08;以后簡稱…

mysql語法替換字符串

UPDATE ht_business_task SET url REPLACE ( url, &amp;, & )轉載于:https://www.cnblogs.com/lz20150121/p/5030739.html

POJ1274 The Perfect Stall(二分圖)

題意&#xff1a; 一些奶牛只有在特定的圍欄中才能產奶&#xff0c;要求合理安排使能產奶的奶牛數達到最大。 要點&#xff1a; 二分圖裸題&#xff0c;最近剛學了二分圖&#xff0c;看下面的參考博客&#xff0c;寫的比較好&#xff1a; 參考博客&#xff1a;匈牙利算法 15479…

藍牙HCI剖析(一)

來自&#xff1a;http://blog.csdn.net/xiaoxiaopengbo/article/details/51334257 一.HCI介紹 HCI提供了訪問bluetooth control的統一接口&#xff0c;通俗來講&#xff0c;就是定義了特定的格式來控制藍牙芯片來做相應的動作&#xff08;比如inquiry,connect,disconnect&#…

c語言題庫2

96. struct name1{ char str; short x; int num; } struct name2{ char str;0 1 2 3 int num; 4 5 6 7 short x; 8 9 10 11 } sizeof(struct name1)? sizeof(struct name2)? 8、12 97. 讀文件file1.txt的內容&#xff08;例如&#xff09;&#xff1a; 12 34 56 …