JavaScript建立物件(三)——原型模式
在JavaScript建立物件(二)——建構函式模式中提到,建構函式模式存在相同功能的函式定義多次的問題。本篇文章就來討論一下該問題的解決方案——原型模式。
首先我們來看下什麼是原型。我們在建立一個函式時,這個函式會包含一個屬性prototype
,這個屬性是一個指標,它指向一個物件——該函式的原型物件,這就是原型,它包含了該函式型別的所有例項可共享的屬性和方法,見下面示意圖:
如圖所示,宣告瞭一個函式Person
。在JavaScript中,一個函式被宣告的同時就具有了一些屬性,其中有一個叫做prototype
,它指向了該函式的原型物件,即上述示例中的Person Prototype
。同時,這個原型物件有一個叫做constructor
的屬性反過來又指向了該函式物件。
當我們建立一個函式的例項時,例如上面的var personObj = new Person(`張三`, 12);
,這個例項也會有一個屬性指向該函式的原型物件,在Chrome的開發工具中顯示為__proto__
。
上面我們說原型的屬性可以被該函式型別的所有例項所共享,那具體是怎麼實現呢?看下面的示例:
function Person(){
}
//給原型新增自定義屬性和方法
Person.prototype.name = `張三`;
Person.prototype.sayName = function(){
console.log(this.name);
}
var p1 = new Person();
//給p1新增age屬性
p1.age = 18;
console.log(p1.name);//張三
console.log(p1.age);//18
p1.sayName();//張三
var p2 = new Person();
console.log(p2.name);//張三
console.log(p2.age);//undefined
p2.sayName();//張三
在上面的程式碼中,我們並沒有給例項新增name
屬性和sayName
方法,但是依然可以通過例項呼叫,貌似例項天生就具有了原型的屬性和方法,其實不是的,下面是在Chrome的開發工具中看到的內容:
我們看到,p1
是Person
型別的,我們給p1
設定了age
屬性,這裡也能看到age
是18
。另外我們看到p1
有個__proto__
屬性,這個就是我們在原型示意圖中說的指向原型物件的屬性。
程式碼讀取物件例項某個屬性的時候會執行一次搜尋,首先搜尋物件例項,如果搜尋到了就返回,如果沒有則會繼續搜尋__proto__
指向的原型物件,搜尋到了就返回。所以上面例子中p1.age
是搜尋到了p1
的age
屬性返回了,p1.name
是搜尋到Person Prototype
的name
返回了,p2.age
在Person Prototype
中也沒搜到,於是返回了undefined
。這就是例項物件共享原型屬性的原理。
除了上面的寫法,原型還有一種更簡單的定義方式,就是用一個包含所有屬性和方法的物件字面量來重寫整個原型物件,這樣避免了每當給原型新增一個屬性就要書寫一遍Person.prototype
的繁瑣,同時從視覺上看也更好地封裝了原型的功能,如下程式碼所示:
function Person{
}
Person.prototype = {
constructor: Person,
name: `張三`,
age: 18,
job: `JavaScript`,
sayName: function(){
console.log(this.name);
}
}
現在回到文章一開始提出的相同功能的函式定義多次的問題,因為函式原型的屬性和方法可以由所有例項所共享,所以只要在原型中定義一次,所有例項就都可以使用,這樣就完美解決了建構函式模式的問題。
總結一下,與建構函式模式相比:
- 原型模式不必在建構函式中定義屬性和方法,而是直接定義在原型中。
- 這些屬性和方法被所有例項共享。
原型模式雖然好用,但也不是沒有缺點。首先,它省略了為建構函式傳遞初始化引數這一環節,結果所有例項在預設情況下都將取得相同的屬性值。其次,最大的問題是由原型的共享本性帶來的,下面來分析一下原型的共享問題。
通過共享,我們解決了建構函式模式相同功能的函式定義多次的問題,所以共享對於函式是有好處的。對於基本型別的屬性,如上面的name
、age
,因為屬性的搜尋機制是從例項到原型,所以可以通過給例項新增一個同名的屬性,遮蔽掉原型中相應的屬性,問題也不大。然而,對於引用型別的資料來說,問題就比較嚴重了。來看下面的示例:
function Person(){
}
Person.prototype = {
constructor: Person,
name: `張三`,
age: 18,
job: `JavaScript`,
friends: [`小明`, `小剛`],
sayName: function(){
console.log(this.name);
}
}
var p1 = new Person();
var p2 = new Person();
p2.name = `李四`;
p1.friends.push(`小紅`);//張三交了個女朋友小紅
console.log(p1.friends);//["小明", "小剛", "小紅"]
console.log(p2.friends);//["小明", "小剛", "小紅"],我擦,小紅怎麼也成了李四的女朋友
console.log(p1.friends == p2.friends);//true
如上所示,Person.prototype
包含了一個引用型別,陣列friends
,其中friends
只是一個指標,[`小明`, `小剛`]
才是真正的物件。通過p1.friends
修改了這個陣列,因為共享的問題,p2.friends
訪問的也是同一個陣列。假如我們的初衷就是共享一個陣列,那麼也沒問題。但是多數情況下應該是不想共享的場景。比如這裡,張三新交了一個女朋友小紅,結果小紅同時也是李四的女朋友,是張三有這癖好?是小紅劈腿?還是人家張三隻是單純地交了個女朋友,被你搞得複雜了?這個說不清,既然說不清,那麼程式就有問題。所以很少有人單獨使用原型模式,那麼這個問題怎麼解決呢?辦法還是有的,那就是組合使用建構函式模式和原型模式,這個實現也很簡單,但為了區分原型模式,後面將會單獨列一篇文章。
本文參考《JavaScript高階程式設計(第3版)》,關於原型模式的其他特點讀者可以查閱第6.2.3章節,裡面有詳細的說明。
相關文章
- javascript 筆記03(建立物件/原型模式/js 繼承/BOM)JavaScript筆記物件原型模式JS繼承
- JavaScript 物件 & 原型JavaScript物件原型
- JavaScript建立物件(一)——工廠模式JavaScript物件模式
- JavaScript之物件和原型JavaScript物件原型
- JavaScript中的原型、原型鏈、原型模式JavaScript原型模式
- 建立型-原型模式原型模式
- Javascript 中實現物件原型繼承的三種方式JavaScript物件原型繼承
- 【20190220】JavaScript-知識點整理:物件建立方式、原型、閉包JavaScript物件原型
- 物件建立模式物件模式
- 建立型模式之原型模式(2.3)模式原型
- 建立模式 02-Prototype(原型)模式原型
- JavaScript嚴格模式(三)- 物件的禁止操作JavaScript模式物件
- 淺談JS物件的建立、原型、原型鏈繼承JS物件原型繼承
- 【設計模式(四)】建立型模式--原型模式設計模式原型
- 設計模式(三)——原型模式設計模式原型
- Java物件建立模式Java物件模式
- JavaScript物件與建立物件的方式JavaScript物件
- 關於JavaScript原型物件那些事兒JavaScript原型物件
- 解說21種設計模式之第一篇_原型模式(物件建立型)設計模式原型物件
- javascript使用new建立物件JavaScript物件
- JavaScript 建立物件的方式JavaScript物件
- 前端戰五渣學JavaScript——物件導向、原型和原型鏈前端JavaScript物件原型
- 說清楚javascript物件導向、原型、繼承JavaScript物件原型繼承
- JavaScript物件導向 ~ 原型和繼承(1)JavaScript物件原型繼承
- 三張圖理解JavaScript原型鏈JavaScript原型
- 從JavaScript學習設計模式-01原型模式JavaScript設計模式原型
- JavaScript物件導向—物件的建立和操作JavaScript物件
- 建立物件的幾種模式物件模式
- JavaScript建立物件的多種方法JavaScript物件
- 談談JavaScript中建立物件(Object)JavaScript物件Object
- 《JavaScript物件導向精要》之四:建構函式和原型物件JavaScript物件函式原型
- 《JavaScript物件導向精要》之六:物件模式JavaScript物件模式
- JS物件導向程式設計(三):原型JS物件程式設計原型
- 原型物件與原型鏈原型物件
- 關於javascript的原型和原型鏈,看我就夠了(三)JavaScript原型
- js基礎--原型物件與原型物件鏈JS原型物件
- 一文帶你徹底理解 JavaScript 原型物件JavaScript原型物件
- Singleton(單例)——物件建立型模式單例物件模式