《javascript高級程序設計》第六章 讀書筆記 之 javascript對象的幾種建立方式

1、工廠模式

工廠模式:使用字面量和object構造函數會有不少重複代碼,在此基礎上改進
圖片描述
解決了多個類似對象的問題,但沒有解決對象識別的問題(即怎樣知道一個對象的類型)segmentfault

2、構造函數模式

圖片描述
與工廠模式建立對象的不一樣之處:沒有顯示建立對象,直接將屬性和方法賦給this對象,沒有return語句。默認return的是this對象。
構造函數自己也是函數,只是能夠用來建立對象,因此借鑑自其餘面嚮對象語言,構造函數始終應該以一個大寫字母開頭,非構造函數用一個小寫字母開頭,用於區別構造函數與其餘普通函數。
new操做符建立對象實例,經歷4個步驟:
一、建立一個新對象
二、講構造函數的做用域賦給新對象(因此此時this指向這個新對象)
三、執行構造函數中的代碼(爲這個新對象添加屬性)
四、返回新對象
上面的實例a又一個constructor(構造函數)屬性指向Person。
圖片描述
相比較工廠模式的有點:有constructor屬相,能夠標誌爲一種特性的類型。
但實際用來檢測對象類型,instanceod更方便些,因此instanceof比較的是constructor屬性。
三種使用構造函數建立對象的方法:
圖片描述數組

call和apply的做用都是在某個特殊對象的做用域中調用Person()函數。那麼上例中,otherPerson的做用域中調用Person函數,this指向otherPerson對象,執行構造函數中的內容,this.name指otherPerson.name=‘shirley’
構造函數模式的缺點:每建立一個實例都要執行一遍構造函數的語句,每一個實例有不一樣的屬性值很正常,也有許多內容如出一轍的方法,這些方法重複建立(實際是new function實例,因此person1.sayname!=otherPerson.sayname。由於sayName方法是不一樣實例,引用地址不一樣)則顯得冗餘。
很明顯,若是實例引用同一個sayName實例(同一個方法)就可以解決上述問題。
圖片描述
Person的sayName引用的都是同一個sayName函數,即全局變量中的sayName函數。瀏覽器

3、原型模式

利用每一個函數都有的一個prototype(原型)屬性。這個屬性是一個指針,指向一個對象,這個對象的用途是包含能夠由特定類型的全部實例共享的屬性和方法。(解決了構造函數模式的缺點)
prototype就是經過調用構造函數而建立的那個對象實例的原型對象。(就是所建立的對象的原型,例如:var person1=new Person(’linda‘,15)person1的原型爲Person。otherPerson=new Object() otherPerson的原型爲Object)
例子:
圖片描述
判斷一個對象的prototype是否指向某對象
圖片描述
訪問一個對象的prototype屬性
圖片描述
Firef、Safari、Chrome中支持一個屬性__proto__能夠訪問到prototype
注意: JavaScript 中任意對象都有一個內置屬性 [[Prototype]] ,在ES5以前沒有標準的方法訪問這個內置屬性,可是大多數瀏覽器都支持經過__proto__來訪問。如下統一使用__proto__來訪問 [[Prototype]],在實際開發中是不能這樣訪問的。(摘自:https://segmentfault.com/a/11...
ES5中增長了一個新方法,Object.getPrototyOf()
圖片描述
「原型最初只包含constructor屬性」即,對象的constructor保存在原型屬性中。
對象實例不能改變原型中的值,因此當咱們試圖改變原型中的值時,會在實例中新添加一個相同名稱的屬性。當咱們訪問這個屬性時,就會優先返回實例中的屬性,這就是覆蓋了原型的屬性。
那麼咱們怎麼肯定一個屬性是來自對象實例仍是來自對象的原型,使用Object對象的hasOwnProperty()方法能夠檢測屬性是否存在於對象實例中,若存在,則訪問的屬性一定是來自對象實例,由於當訪問一個屬性時,先搜索對象屬性若不存在纔會去搜索對象的原型屬性的。
圖片描述
delete能夠刪除實例的屬性,但不能刪除對象原型中的屬性。
對象、構造函數(constructor)和原型(Prototype)的聯繫:
以下圖
圖片描述安全

person1和person2實例中的prototype屬性中保存的是Person的原型,原型裏有constructor屬性又指向Person。因此對象和constructor之間是經過原型聯繫起來的。app

肯定屬性是原型中的屬性:
in操做符只要經過對象可以訪問到屬性就返回true,不論是實例的屬性仍是原型中的屬性,因此經過in操做符返回true兒hasOwnProperty()返回false就能夠肯定屬性是原型中的屬性。函數

用字面量法定義Person的prototype屬性:
圖片描述
會形成constructor屬性再也不指向Person
咱們知道,沒建立一個函數,就會同時建立它的prototype對象,這個對象也會自動得到constructor屬性。使用字面量定義prototype會重寫這個對象,所以constructor會變成新的對象的constructor屬性(指向object構造函數)。
打印person2顯示:
圖片描述
紅框內沒有constructor屬性。咱們知道person2.constructor會尋找person2對象中的constructor對象中的constructor對象,person2實例對象中沒有,尋找原型中(紅框)也沒有,繼續尋找prototype的原型對象即object對象,因此,person2.constructor===Object true;
圖片描述
原型模式建立對象是在函數構造模式的基礎上解決共有方法和屬性的,那麼函數構造模式是爲了解決字面量法的沒法判斷是哪一個對象的問題而出現,怎麼判斷?經過對象的constructor屬性判斷,如今原型的constructor都指向對象,就把這個優點抹去了,因此出現下面這樣的方法來保存這個特性。
圖片描述
這樣作與原來的差異是:constructor屬性的[[Enumberable]]特性被設置爲true,原來是false(不可枚舉)。因此若是使用兼容EXMAScript5的JavaScript引擎,可使用Object.defineProperty()
圖片描述
原型具備動態性。
構造函數的原型改變會當即反映到全部實例中,但若是是從新寫一個原型對象則不會了this

圖片描述
圖片描述
緣由:person1的構造函數會自動指向一個原型對象,而保存的是這個原型對象的指針,新建一個prototype對象後,在堆內存中開闢了一個新的對象空間,在person2中保存的是這個新對象的引用指針,因此二者不一樣。
原型模式不多會單獨使用,由於全部屬性都是共享的,但實力通常都是要有屬於本身的所有屬性的。原型模式沒法作到,因此這是原型模式的缺點。spa

4、組合使用構造函數和原型模式

建立自定義類型的最多見方式,構造函數模式用於定義實例屬性,原型模式用於定義方法和共享的屬性。
圖片描述
結果每一個人實例都有本身的一份實例屬性的副本,同時又共享着對方法的引用,最大限度地節省了內存。這種方式還支持向構造函數傳遞參數。(既有構造函數模式的優勢又有原型模式的優勢)prototype

5、動態原型模式

在構造函數中判斷是否存在sayName函數,若是不存在添加到原型中,下圖建立了兩次對象,調用兩次構造函數,但if的判斷只執行一次,在第一次執行。3d

圖片描述

6、寄生構造函數模式

與工廠模式在寫法上紅框圈出不一樣以外如出一轍。叫法上把Person函數叫作構造函數,其餘無區別
圖片描述
適用情境:
能夠在特殊的狀況下用來爲對象建立構造函數。假如咱們想建立一個具備額外方法的特殊數組。
圖片描述

7、穩妥構造函數模式

穩妥對象:沒有公共屬性,並且其方法也不引用this的對象。
穩妥對象最適合在一些安全的環境中(這些環境中會禁止是使用this和new),或者在防止數據被其餘應用程序(如Mashup程序)改動時使用。
穩妥構造函數與寄生構造函數相似的模式。不一樣點:一、新建立對象的實例方法不引用this,二、不適用new操做符調用構造函數。

圖片描述因此,使用穩妥構造函數模式建立的對象與構造函數之間沒有關係,沒法用instanceod判斷所屬類型。之因此穩妥,是由於除了sayName方法外部沒法對傳入構造函數中的原始數據進行訪問。即便能夠給這個對象添加方法或數據成員。使用環境:某些安全執行環境下使用(ADsafe和Caja)

相關文章
相關標籤/搜索