JavaScript prototype背後的工作原理
from http://www.nowamagic.net/librarys/veda/detail/587
“prototype”字面翻譯是“原型”,是javascript實現繼承的主要手段。粗略來說就是:prototype是javascript中的函數(function)的一個保留屬性,並且它的值是一個對象(我們可以稱這個對象爲"prototype對象")。
通過以此函數作爲構造函數構造出來的對象都自動的擁有構造函數的prototype對象的成員屬性和方法。
其中的要點是:
- prototype是函數(function)的一個必備屬性(書面一點的說法是"保留屬性")(只要是function,就一定有一個prototype屬性)
- prototype的值是一個對象
- 可以任意修改函數的prototype屬性的值。
- 一個對象會自動擁有這個對象的構造函數的prototype的成員屬性和方法。
02 |
var function1= function (){ |
03 |
this .name= "function1" ; |
04 |
this .saySomething= function (){alert( "This's
a method of " + this .name);} |
08 |
var function2= function (){ |
13 |
function2.prototype= new function1(); |
14 |
var obj1= new function1(); |
當然,上述例子離真正實際上使用的“繼承”還相差甚遠,但也體現出繼承的意義:一個對象擁有了另一個對象的屬性和方法。(如兒子擁有了老爸的血型和脾氣,人類繼承了動物的本能如進食和打鬥等等)
以上部分大概闡述了prototype的概念和作用,但單憑這些還不夠對prototype加深認識。現在來看看prototype背後是怎樣工作的:
先來看看用new形式創建對象的過程:
這個過程是這樣的:javascript引擎首先遇到了關鍵字new後,馬上開闢了一塊內存,創建了一個空對象(並且將this指向這個對象),接着執行構造函數func()對這個空對象進行構造(構造函數裏面有什麼屬性和方法都一一給這個空白對象裝配上去,這也就是爲什麼構造函數叫“構造函數”的原因)。
其實,new和執行構造函數之間還有一件事引擎沒有顯式地告訴我們,而是偷偷地做了,這就是給這個空對象賦予prototype對象。
這裏不得不提到一個跟prototype一樣同樣是系統保留而且同樣重要的東西:__proto__
__proto__是一個對象自動擁有的內置屬性(請注意:prototype是函數的內置屬性,__proto__是對象的內置屬性,但它們最終都指向同一個對象,就是那個用來被繼承的對象),用chrome和FF都可以訪問到一個對象的__proto__屬性,IE就不可以。
正是一個對象的__proto__指向着這個對象的構造函數的prototype對象,才使這個對象認識了它的構造函數的prototype對象,並擁有了這個prototype對象的屬性和方法。
所以var obj=new func()這個過程更具體是這樣的:
- javascript解析引擎遇到new後,開闢一片內存並創建了一個空對象,並且將“this”指向這個空對象
- javascript解析引擎將這個空對象的__proto__指向後面緊跟着的構造函數默認的prototype對象(一指向到prototype對象後,解析引擎就知道了“噢,這個對象要擁有這個prototype對象的屬性和方法了”)
- javascript解析引擎執行構造函數體內的代碼,也就正式開始對這個空對象進行構造(或者說裝配)的過程了(this.name="xxx",this.sayHello=function(){...}等等)
- 對象被構造裝配好,並賦值到等號左邊的變量。