第一次記錄本身學習的腳步,我選擇了JavaScript中自認爲比較熟悉的一小部分來講,誠摯的但願可以獲得各位前輩的批評與指正。而對於看到我這篇筆記但願從這篇筆記中收穫知識的讀者,我但願大家能夠參考權威,擁有本身的真知灼見而不聽我一家之言,以避免有不正確的地方誤導了讀者。函數
**1.原型(prototype)是函數的一個屬性,這個屬性是個指針指向原型對象。
2.原型對象(prototype object)是一個屬於其所在函數的空對象,能夠經過它給函數添加屬性和方法。**
值得注意的是原型對象也擁有一個屬性——constructor指向其函數。學習
經過一張圖咱們能夠更好的理解這幾者的關係:this
上圖給咱們傳達了幾個信息:
**1.實例擁有一個屬性[[prototype]],這個屬性指向其構造函數的原型對象。
2.原型對象也是構造函數的實例**spa
咱們知道,JavaScript是一個基於對象的語言,而與Java等語言不一樣的是JavaScript沒有類的概念。而要實現類的功能咱們則須要模擬類。在模擬類的實現中使用原型和原型對象咱們就能夠更好的建立具備封裝性,共享性的類(對象),而這種建立類(對象)的模式就叫原型模式。prototype
這也解釋了爲何在《JavaScript高級程序設計》中描述原型以及原型對象用於建立對象,而在《JavaScript權威指南》中描述原型以及原型對象用於建立類。(由於在JavaScript中沒有類,有類也只是對象模擬出來的,包括ES6中的class關鍵字)設計
原型模式模擬類十分簡單:指針
var Foo = function(){} Foo.prototype.username = 'ec' console.log(Foo.prototype) // --> a{username = 'ec'} var f = new Foo() console.log(f.username) //--> 'ec' console.log(Foo.username) //--> underfined
咱們能夠發現兩個信息:
**1.原型對象與它所在函數同名
2.屬性已經被添加進了原型對象中
3.使用時必須實例化構造器函數。**code
須要注意的是原型模式模擬類是有缺點的,例如如下代碼:對象
function Person(){} Person.prototype = { constructor: Person, name: "李小山", age: 20, family: [ "李大山", "張曉梅", ], } var person1 = new Person() var person2 = new Person() person1.family.push("李巨山") console.log(person1.family) //--> ["李大山", "張曉梅", "李巨山"] console.log(person2.family) //--> ["李大山", "張曉梅", "李巨山"]
從上面這個例子咱們能夠獲得幾個信息:
**1.由於原型模式規定咱們在原型對象上添加屬性與方法,因此沒法傳遞初始化參數
2.由於過分的「共享」以致於當一個實例改變了引用類型的值,全部實例的該值都會被改變。**blog
以上的緣由就形成了不多有使用純的原型模式建立對象,而其餘混合使用原型模式的建立對象模式就不在這裏展開說了。
終於講到了這部分,這個部分咱們能夠提一個更加具體的問題:
原型對象與對象、函數、構造函數、實例的關係是什麼?
首先是函數與構造函數的區別:
而實例就是構造函數建立出來的對象,擁有構造函數的屬性與方法。
知道了這些後咱們就能夠經過這張圖來明確它們之間的關係了:
這個圖看似唬人,其實只須要知道三點就能夠秒懂了:
1.JavaScript中一切皆是對象
2.全部對象有[[prototype]]屬性,指向其構造函數的原型對象
3.全部函數都有prototype屬性,指向其原型對象
4.全部實例都有constructor屬性,指向其構造函數
圖中有兩個地方可能比較難以理解:
由於內置對象Function()也是函數,而函數就是function,這就形成了一種雞生蛋、蛋生雞的問題,而讓Function()的原型對象爲函數對象就能夠添加函數方法給Function(),這也解釋了爲何Function()的[[prototype]]屬性也指向其原型對象。
這也是一個雞生蛋、蛋生雞的問題,是對象建立了對象,那麼追根溯源誰真正建立了對象呢?答案就是Null空。(圖中這個地方箭頭指向錯誤,望見諒)
至此,咱們算是大體瞭解了JavaScript中有關於原型的基本知識了,其實還有不少問題咱們沒有解決,好比比原型模式更好的建立對象模式,還有關係圖中有關於繼承的部分都還沒用詳細說明。篇幅有限,下次再聊。