理解原型模式,首先要理解prototyoe(這個單詞翻譯 原型)屬性,《javascript高級程序設計》書中描述到——我們創建的每個函數都有一個prototype屬性,這個屬性是一個指針,指向一個對象,而這個對象的用途是包含可以由特定類型的所有實例共享的屬性和方法。
我在上一篇構造函數模式所說的,我們構建了一個一個Person函數,然后通過new一個person函數來創建了person1實例,person2實例,既然每個函數都有一個prototype屬性,那么我有幾個問題想要弄明白:
- person1的prototype屬性指向哪個對象?
- Person對象也是我們創建的一個函數,它有沒有prototype屬性,如果有,它的prototype屬性又指向哪?
第一個答案,person1的prototype屬性指向Person對象 (這個應該能理解吧)
那么第二個問題看起來就有些奇怪,Person對象的prototype的屬性指向哪啊?它可以我們自定義的,可不是一個實例。答案是Person對象的prototype屬性指向Person對象(如果我沒理解錯的話)
這聽起來是挺別扭的,函數的原型對象是它本身,但是,它的真實構造是這樣的:
當我們創建了一個自定義的構造函數(假設為Person)后,自定義構造函數的prototype屬性指向原型對象,但是每個原型對象中有一個constructor(翻譯 構造函數)屬性,這個屬性指向我們的自定義函數。說到這里,大家就應該能理解為什么我說Person對象的prototype屬性指向它本身。我給大家舉個形象生動的例子啊(僅供參考)。Person是一個人,他的左手叫prototype,有一天他想找他的原型對象,他把左手伸出去找啊找啊的,一下抓到一個匹配的原型對象的右手(constructor),他順着原型對象的右手往上看原型對象的臉,咦,這不是我么?person1有一天也想找原型對象了,他也伸出他的左手(prototype)去找啊找啊,抓到了一個匹配的原型對象的右手,他也順着原型對象的右手往上看,咦,這不是Person么!
哈哈,希望能逗大家一笑,那么我有一個問題
3.prototype屬性有什么用?
function Person() {} Person.prototype.name="guoshiwei"; Person.prototype.age=23; Person.prototype.sayName=function(){ alert(this.name) }; var person1=new Person(); person1.sayname(); //"guoshiwei" var person2 = new Person(); person2.sayName() //"guoshiwei" alert(person1.sayName == person2.sayName); //true
當我們需要一個所有實例都需要的屬性或方法時,可以把它添加到原型對象上,所有實例都能共享這些屬性或方法,我們可以看到,person1和person2引用同一個原型對象,換句話說,只要是通過new Person()創建的實例對象,他們都引用同一個原型對象
還有一些問題
Person.prototype.name= "guoshiwei"; Person.prototype.age=23; var person1=new Person(); person1.name="bushiguoshiwei"; alert(person1.name) // "bushiguoshiwei" alert(person1.age) //23 delete person1.name; alert(person1.name); //"guoshiwei"
通過這段代碼,我們可以理解對象原型和實例對象是怎樣工作的,當我們調用實例中的屬性和方法時,我們先看實例對象本身的屬性和方法有沒有這個屬性和方法,如果有,就調用,如果沒有,那我們就去這個實例對象的原型對象中找這些屬性或者方法,如果有,就調用,如果沒有就報錯(是報錯還是顯示undefined啊?我也不太清楚)。如果不清楚這種向上查詢的意思,可以去了解一下原型鏈,《javascript高級程序設計》第四章,這章挺重要的,原型鏈還涉及到后面閉包的問題。
不知道大家想過沒有,能不能通過實例對象修改原型對象的屬性或方法啊?
function Person(){ } var person1= new Person(); person1.prototype.name = "guoshiwei"; var person2= new Person(); alert(person2.name); //報錯,person1.prototype is undefined(火狐)
是不是實例對象只能引用原型對象,而只有構造函數可以添加或刪除(能刪除嗎?) 或者說原型對象中的constructor屬性指向誰誰才能操作原型對象?
總的來說:構造函數模式可以創建可以標識的實例,並且實例可以具有構造函數中的屬性或方法,而原型模式可以把需要共享的屬性或者方法添加到原型對象中,減少了實例中的方法的重復創建,所以,構造函數模式和原型模式混合使用時目前最常用的方法!