js原型與繼承

0.要弄懂原型與繼承 先要能夠回答如下5個問題

1.js對象是如何分類的及系統的創建方法

2.prototype是什麼

3.__proto__是什麼

4.prototype.constructor是什麼

5.他們相互之間有什麼關係


提出這些基礎問題,才能夠徹底理解js的原型與繼承,當然你不用自己思考答案了,下面就是答案


1.對象分類

先看簡單的代碼

var obj={};//普通對象

function fun(){}   //fun叫函數對象

fun.prototype;   // 原型對象

js對象分成3類 由Obje創建的 叫普通對象,由Function創建的叫函數對象,伴隨函數對象創建的prototype屬性叫原型對象。

var obj={}; 是一種創建對象的語法糖,其本質是var obj=new Object(); 

定義一個函數 function fun(){},也是語法糖 其實質是調用var fun=new Function();

其實Object是一個函數對象 因爲他也是Function創建的,所以可以說 普通對象是由函數對象創建的,函數對象是由Function創建;原型對象的特殊性看下面介紹。

這裏就說明了普通對象 和函數對象的創建方法以及相互關係。

總結 對象根據特殊性可分成三類 函數對象  原型對象 普通對象


2.普通對象的隱式原型__proto__屬性說明

obj普通對象必定有隱式原型 __proto__屬性,__proto__它提供了 普通對象obj的繼承信息,這就是原型繼承。

在執行new Objec()時系統爲自動爲普通對象創建 隱式原型__proto__屬性。

那obj.__proto__指向誰,繼承信息就來自於誰。該prototype 出場了,obj.__proto__指向Object.prototype ,它提供obj的繼承信息。


3.函數對象的 prototype  屬性說明

函數對象,他們有三個屬性 prototype ,constructor  , __proto__,

function fun(){} 這樣定義的函數中 fun是一個函數對象,他的constructor就是Function ,prototype是一個普通的object對象,_proto_指向Function.prototype. 要暈了吧

fun.constructor 指向他的構造函數 Function這個好理解,因爲是Function構建了他,

fun.prototype ,先看var objByFun=new fun(); objByFun._proto_就指向fun.prototype 他是給普通對象提供繼承信息的,也就是原型繼承;

創建fun函數時, 系統就自動創建fun對象以及他的prototype原型對象. 

prototype原型對象又是一個什麼東西呢


4.原型對象prototype說明

prototype對象是本質是一個普通對象 ,不過他很特殊, 有一個constructor屬性 ; 他指向對應的函數對象,即fun.prototype.constructor===fun爲true;

這種關係的簡單記憶法: 因爲要創建函數對象伴隨着產生了原型對象,所以原型對象的constructor指向他的創建者函數對象,重複理解 :系統因爲要創建fun函數對象,所以伴隨着產生了fun.prototype原型對象,爲了記住祖宗 所以fun.prototype.constructor指向fun函數對象。

原型上有一個constructor屬性有什麼好處呢,造物主爲什麼要這樣設計-------因爲這樣函數對象創建的普通對象就能夠繼承到這個屬性,就可以很簡單的訪問到對應的函數對象/構造函數。

列如 function Test2(){}; var obj2=new Test2();   obj2.constructor ===Test2 就爲true; 知道一個普通對象的構造函數有什麼用,我想到的是深度複製時可以使用。當然其他的情況靠大家去用了 函數對象上如果還有其他自定義的屬性 方法等,那訪問起來就很方便了。

 還有一個問題prototype對象 創建他的函數是誰呢 ,是Object創建的,

類似這樣的代碼  new Object({constructor:'對應函數對象'}) ,這裏有一個不明顯的知識點,原型對象既然是Object函數創建的,所以原型對象還有一個自有屬性 隱式原型__proto__,它指向Object.prototype.

這裏總結一下 自動生成的原型對象最大的特徵是constructor沒有指向自己的構造者,而被重置爲對應的函數對象

爲什麼要區分自動生成的原型對象?,如果你覆蓋原型對象,constructor屬性就會指向真實的創建對象

看如下代碼

function Test(){    }

  Test.prototype={bb:45};

  這個時候  Test.prototype.constructor 就指向Object了

覆蓋後原型對象就徹底變成了一個普通對象 ,當然你也可以手動設置回來, 如讓 Test.prototype.constructor=Test;

原型對象與普通對象的區別 就是看constructor是否真實的指向自己的構造函數,另外還有是自有還是繼承來的,普通對象constructor是繼承來的,原型對象是constructor屬性是自有的。


在這裏補充一個隱藏的知識點,函數的創建過程 :

js上帝用Function創建了函數對象,然後又用Object創建了它的原型對象,然後原型對象有普通對象的全部特徵。


5.函數對象深度說明

首先 要理解 Object由於是函數對象,所以他是Function創建的,一切函數對象都是new Function創建的,

那麼相對於Function而言 函數對象也是普通對象,他們就從Function.prototype屬性上繼承信息,普通對象就有隱式原型__proto__ ;

所以就有結論 

a.函數對象 一定有兩個自有屬性 prototype 和__proto__; 

b.原型對象prototype一定有兩個constructor,__proto__屬性。

c.普通對象一定有   一個  __proto__自有屬性,


6.Object 與Function的關係

看到這裏,最大的Boss要出場了,他們兩個之間有什麼關係呢。

a.Object是Function創建的 ,

所以 Object.__proto__===Function.prototype 爲true,   Object.constructor===Function 爲true.


b. Function.prototype 原型對象 是Object創建的  所以有

Function.prototype.__proto__===Object.prototype 爲true

符合那句話特徵:函數對象Function創建,原型對象Object創建,掌握這句話 就好記住這個關係了。

a ,b兩條已經說清楚了 Object 與Function的關係,但是有兩個問題還存在Object.prototype是誰創建的,Function 是誰創建的  


Object.prototype是誰創建的

Object.prototype,他有一個特徵 Object.prototype.__proto__===null爲true ,說明他不從任何對象那裏繼承屬性,而普通對象一般都從Object.prototype對象上繼承屬性, Object.prototype是原型繼承鏈的頂端。

不繼承任何屬性的對象如何創建?萬能的Object提供了Object.Create方法可以創建,代碼如下

Object.prototype=Object.Create(null); 這樣創建的對象就不繼承任何屬性了

總結 Object.prototype=Object.Create(null); 創建了Object.prototype原型對象

Function 是誰創建的  

是js上帝創建的了

打印Function.__proto__得到的是 ƒ () { [native code] }

打印 Function.constructor 得到的是 ƒ Function() { [native code] }



7.從js看如何創建一門編程語言

創建  js 這門語言 其實首先定義一條原型繼承的規則,底層實現 Function對象的邏輯,然後用Function就可以構造各種對象了,其中把Object特殊化 讓他承擔起原型繼承的重任。

js一門解釋執行的語言,定義解釋規則時 其實只要定義好Function的解釋規則就行,因爲一切對象都可以抽象成由Function直接或間接創建 。

當然這裏我有點猜,不過不要緊 ,猜也是人們創建基本認知的過程,對錯的認知都會讓人遠離陌生未知帶來的恐懼。


最後用一句話總結 《道德經》第四十二章首句:道生一,一生二,二生三,三生萬物   -------------js語言創建過程也是這樣 。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章