一提及JavaScript就要談的幾個問題,原型就是其中的一個。說了句大話,史上最清晰。原本是想按照大綱式的行文寫一下,但寫到後邊感受其實就一個概念,沒有什麼條理性,因此下面就簡單按照概念解釋的模式談下這個問題。javascript
1.JavaScript的原型是什麼?java
原型,首先他是個對象。和在以對象爲核心的JavaScript這門語言中的其餘普通對象來講同樣,只不過他的角色有點特殊。但首先要明白他就是一個對象,是一個無序的屬性和值的序列對。函數
2.誰會具備原型這個對象?this
全部的對象(包括函數這個對象)在默認的狀況下都有一個原型對象。這句話的理解就和普通對象中再嵌套擁有對象是一個意思。prototype
由於原型自己也是對象,因此每一個原型自身又有一個原型對象(屬性繼承就是這麼來的)。照這句話下去的話會成爲一個無限繼承的模式,因此必定會有一個結束點。因此例外來了,當對象原型追溯到原型鏈的最頂端的時候,這個最頂端的位置也就是在這種層層向上的關係到了Object這個構造函數的prototype,Object函數的的prototype對象以下圖:對象
從圖中能夠看到,Object的屬性裏已經沒有了__proto__。至於什麼是__proto__,下邊會講。blog
3.__proto__和prototype分別是指什麼?繼承
每個對象都有一個__proto__對象屬性,每個函數(函數也是對象)都有一個 prototype對象屬性,因此總結來講就是每個對象有一個__proto__,而每個函數都有一 個prototype,但同時他又是一個對象,因此函數也會有__proto__。ip
4.__proto__和prototype的關係是怎麼樣的?原型鏈
首先明白對象是怎麼來的?對象無非是構造函數構造出來的或者是字面直接量的形式。
構造出來的對象的__proto__指向構造該對象的構造函數的prototype;字面直接量的對象的__proto__指向該對象類型所對應的的構造函數的prototype。
總結來講就是對象的__proto__指向該對象所對應的構造函數的prototype。
5.不一樣函數的prototype分別是什麼?
其實這是兩個問題,第一先回答不一樣函數。
首先JavaScript中只要是函數,均可以用new關鍵字看成構造函數來使用。可是,有些函數是咱們本身實現的,還有一些函數是JavaScript語言標準裏已經規定內置實現的。這些函數包括Array、Boolean、Date、Number、String、RegExp、Math。這裏會有一個問題就是Math他是一個對象而不是函數,你能夠去typeof檢測一下。除去Math以後剩餘的這些內置構造函數的prototype屬性也是語言內置實現的,好比Array裏咱們經常使用的那些pop、push、shift這些方法,都通通包括在Array這個構造函數的prototype對象屬性裏。除了上面提到的內置構造函數外,其他的函數都是咱們本身定義的函數,他們也會有prototype屬性,可是若是咱們不顯示的去給prototype賦值的話,他就是一個空對象。
接下來回答第二個問題,prototype是什麼。
其實上面已經說的很清楚了,prototype是函數的一個固有屬性,即只要是個函數都會有的屬性,內置的構造函數已經有實現好的prototype,它裏邊包括各類方法或者屬性。而咱們本身實現的函數也一定會有一個prototype屬性,可是若是咱們不顯示賦值的話,他就是一個空對象。
6.那咱們所說的原型和原型繼承究竟是什麼意思?
若是你一字不落的看完上邊的全部概念並且能理解到80%以上,就應該很天然的得出這個問題的答案了。
咱們通常所說的原型就是對象的原型,對象的原型是指_proto_這個對象。而全部的對象的繼承也是經過他來實現的。第4個問答中已經很明確了,__proto__指向該對象的構造函數的prototype,而該對象的構造函數的prototype做爲對象會擁有一個__proto__,而這個__proto__又指向他的構造函數的prototype,層層向上,直到__proto__指向Object這個最頂端的函數對象的prototype,也就是第二條的圖所示的便結束。
如上即是JavaScript經過原型繼承的一個解釋。
總結:咱們該怎麼掌握原型這個概念。
掌握一個東西,無非也就是 是什麼,怎麼樣,怎麼用這三點。
是什麼。
首先明白__proto__和prototype,對象都會有__proto__,包括函數對象,函數對象除了__proto__,還擁有prototype。
原型是一個對象,指__proto__,每一個對象都會擁有這個屬性。__proto__指向該對象構造函數的prototype。__proto__的層層向上追溯的過程就是繼承的過程,直到追溯到最頂端即Object這個構造函數的prototype。
怎麼樣。
怎麼樣也就是爲何的意思,原型之因此存在,是基於JavaScript這門語言的面向對象思想來講的。像其餘語言都會有OO和繼承等這些特性,JavaScript雖爲腳本語言,靈活卻不失功用,這個是他實現面向對象和繼承的一個思想。能夠簡單的理解爲此。
怎麼用。
這個是個很大的話題,能夠另開一篇文章來闡述。這裏只是簡單的舉幾個例子。
若是僅僅只是由於爲了給一個實例添加屬性而使用原型是沒有多大意義的,這和直接添加屬性到這個實例是同樣的,假如咱們已經建立了一個實例對象 ,咱們想要繼承一個已經存在的對象的功能好比說Array,咱們能夠像下面這樣作:
var a = [1, 2]; a.__proto__ = Array.prototype; console.log(a.length); //2
又好比咱們本身實現了一個構造函數,上面已經說到,本身實現的函數的默認prototype是一個空對象,因此由這個構造函數建立生成的對象的__proto__指向的是一個空對象。咱們這時候就能夠用prototype來繼承或者實現一些事情。
var MyFun = function (x, y) { this.x = x; this.y = y; }; MyFun.prototype.getArea = function () { return this.x * this. } var obj = new MyFun(2, 3); var area = obj.getArea(); console.log(area); //6
寫完才發現,可能這是史上最不清晰的闡述。但若是你對原型已經有了只知其一;不知其二卻仍是有點模糊的話,好好的從頭讀到結尾,你會發現,原來掌握這個概念也是這麼簡單。
完!祝好運。