最近在學習javascript的原型,發現了__proto__與prototype,學問很大,於是研究了一下。
首先解釋一下什麼是原型。
原型是一個對象,其他對象可以通過它實現屬性繼承。
對象又是什麼呢。
在javascript中,一個對象就是任何無序索引值對的集合,如果它不是一個主要資料類型(undefined,null,boolean,number,array,string),那它就是一個對象。
那麼如何查看一個對象的原型是啥呢。又如何給一個對象設定原型呢。
標準對象原型訪問器Object.getPrototype(object),到目前為止只有Firefox和chrome實現了此訪問器。除了IE,其他的瀏覽器支援非標準的訪問器__proto__,而prototype則是一個只有函數才具有的屬性,
也就是說,如果這個對象不是函數,那麼它就沒有prototype這個屬性。
下面代碼證實了以上結論。
<script>var a={name:'derek'};var b=function(name){name=this.name;};document.write(a.prototype+"<br>");//undefined 對象a顯然不是一個函數,所以沒有prototype這個屬性。document.write(Object.getPrototypeOf(a)+"<br>");//[object Object]document.write(Object.getPrototypeOf(b)+"<br>");//function Empty() {}document.write(Object.getPrototypeOf(b)==b.__proto__);//true 這兩個的是等價的,只不過瀏覽器的相容型不同。</script>
再說一下javascript的建構函式
1、建構函式和普通的函數一樣,但是具有以下兩個特殊性質。
2、通常建構函式的首字母是大寫的(讓識別建構函式變得更容易)。建構函式通常要和 new 操作符結合,用來構造新對象。
下面這個例子很厲害~
基於所知道的知識,請想象建立一個新的對象,並讓新對象表現地像數組的過程。一種方法是使用下面的代碼。
| 1 2 3 4 5 6 |
// 建立一個新的Null 物件 var o = {}; // 繼承自同一個原型,一個數組對象 o.__proto__ = Array.prototype; // 現在我們可以調用數組的任何方法... o.push(3); |
雖然這段代碼很有趣,也能工作,可問題在於,並不是每一個 JavaScript 環境都支援可寫的 __proto__ 對象屬性。幸運的是,JavaScript 確實有一個建立對象內建的標準機制,只需要一個操作符,就可以建立新對象,並且設定新對象的 __proto__ 引用 – 那就是“new”操作符。
| 1 2 |
var o = new Array(); o.push(3); |
JavaScript 中的 new 操作符有三個基本任務。首先,它建立新的Null 物件。接下來,它將設定新對象的 __proto__ 屬性,以匹配所調用函數的原型屬性。最後,操作符調用函數,將新對象作為“this”引用傳遞。如果要擴充最後兩行代碼,就會變成如下情況:
| 1 2 3 4 |
var o = {}; o.__proto__ = Array.prototype; Array.call(o); o.push(3); |
函數的 call 方法允許你在調用函數的情況下在函數內部指定“this”所引用的對象。當然,函數的作者在這種情況下需要實現這樣的函數。一旦作者建立了這樣的函數,就可以將其稱之為建構函式。
我們來測試一下,
var Person=function(name,age){this.name=name;this.age=age;document.write("hello,I'm "+name+" and "+age+" years old"+"<br>");}var p1=new Person('derek',23);document.write(Object.getPrototypeOf(p1)==Person.prototype);//truedocument.write(p1.__proto__==Person.prototype);//true 兩種訪問對象原型的方式會得到相同的結果,前提是非IE6、7、8瀏覽器。。
可以上面的理論是正確的~
我們接著做實驗,看一下繼承是怎麼實現的~
var Person=function(name,age){this.name=name;this.age=age;document.write("hello,I'm "+name+" and "+age+" years old"+"<br>");}Person.prototype.smile=function(){document.write("O(∩_∩)O~"+"<br>");}var p1=new Person('derek',23);p1.smile();
輸出: hello,I'm derek and 23 years old
O(∩_∩)O~
首先,p1這個對象沒有smile這個函數,於是去__proto__屬性上去找,因為p1.__proto__==Person.prototype,而Person.prototype上恰好有這個函數,因此就會出現上面的運行結果。這個是最簡單的原型鏈,如果Person.prototype上還沒有smile()這個函數,那麼就會去Person.__proto__去繼續找,依次類推。