理解原型設計模式以及 JavaScript中的原型規則(原文地址)
1、原型對象:我們創建的每一個函數(JavaScript中函數也是一個對象)都有一個原型屬性 prototype,原型屬性實質上是一個指針,它指向一個對象,這個對象的用途是包含可以由特定類型的所有實例共享的屬性和方法(通俗的說:就是這個特定類型的所有實例都可以共享原型對象包含的屬性和方法)。
2、原型對象的兩賦值方式:
①:
此時實例對象 person1 和 person2 的屬性和方法都是用原型對象共享的,所以上面結果是:
②:
和創建一個引用對象一樣,也可以采用字面量的形式給原型對象賦值。最終結果和上面結果相同,但是一個例外就是 constructor 屬性不再指向Person了,因為字面量的方式重寫了原型對象,此時 constructor 屬性指向Object對象
但是我們可以指明 constructor 指向Person:
3、原型對象的內存分析:
引用《javascript高級程序第三版》中的內存分析圖
Person構造函數、Person原型對象、Person現有的兩個實例之間的關系:
每個函數都會有一個原型屬性(prototype),它是一個指針,指向原型對象;默認情況下,原型對象包含一個constructor(構造函數)屬性(原型最初只包含constructor屬性),這個屬性包含一個指向prototype屬性的指針;如上圖:Person.prototype.constructor指向Person,通過這個構造函數就可以繼續為原型對象添加其他的屬性和方法。
當調用構造函數創建一個新實例后,該實例內部會包含一個內部屬性(指針),它指向構造函數的原型對象;這個連接存在於實例與構造函數的原型對象之間,而不是存在於實例和構造函數之間;也就是說這個內部屬性和構造函數沒有直接的關系。
4、原型對象中的值不能被對象實例重寫:
測試結果:
可以看到原型對象中的name屬性沒有被改變,person1.name來自實例,person2.name來自原型。
在原型模式中當通過person1.name讀取屬性值時,首先會去實例上查找有沒有名稱為name的屬性,有的話就不會再去原型對象上查找;如果實例上沒有,就會去原型對象上搜索。
也就是說當我們給實例上添加了一個屬性,這個屬性就會阻止我們去原型上訪問這個同名屬性,但是不會修改那個屬性。
內存分析,圖中省略了與Person構造函數之間的關系:
通過delete操作符可以直接刪除實例中的屬性:delete person1.name
5、原型的動態性:
第4點說了不能通過對象實例來修改原型對象中的值,不是說原型對象中的值不能被修改,通過下面方式仍可進行修改:
測試結果:
由於在原型中查找的過程是一次搜索,因此在對原型對象上做的任何修改都會立即從實例上反映出來,即使是先創建實例后修改原型也是如此:
測試結果:
內存分析:
但是如果在先創建實例后修改原型的情況下,用字面量賦值的方式來重寫原型對象,這就會切斷現有原型與任何之前存在的對象實例之間的聯系(不是先創建實例后修改原型的情況下仍然可以用這種方式重寫原型對象)
測試結果:
內存分析:
(圖引用《JavaScript高級程序設計第3版》,圖中值未改,原理一樣)
6、原生對象的模型:
所有原生引用類型(Object、String、Array等)都在其構造函數的原型上定義了方法,例如:Array.prototype.sort()、Array.prototype.substring()等,通過原生對象的模型不僅可以讀取到所有默認方法的引用,還可以像修改自定義對象的原型一樣修改原生對象的原型,所以也可以給原生對象添加方法,但是在實際運用中我們不要這樣去修改原生對象的模型(命名沖突、重寫原生方法等等問題都是我們在實際開發中所不希望遇到的)。
7、關於原型對象的幾種操作:
1)isPrototypeOf檢測實例對象是否包含指向某個原型對象的指針,包含返回true,否則返回false。
2)Object.getPrototypeOf(實例對象),返回的就是這個對象的原型,下面結果為true
Object.getPrototypeOf(person1).name,通過這種方式可以訪問原型對象上name的值
3)hasOwnProperty(從Object中繼承而來),檢測一個屬性是否存在於實例中,是就返回true,否則返回false
用 in 也可以檢測屬性值,只不過用這種方式檢測的,無論屬性在實例中還是在原型中都會返回true
4)Object.keys(原型對象),返回一個包含所有可枚舉屬性的字符串數組
測試結果:
8、原型對象的缺點:
原型對象的好處是原型對象上的所有屬性和方法可以被很多實例共享,缺點是當原型中包含引用類型的值的屬性時,一個實例對象對這個引用類型的的屬性做了修改,在其他實例對象中也可以體現:
9、好的實踐:
1)組合使用構造函數模式和原型模式
2)動態原型模式