js創建自定義對象的幾種方式


1. 對象字面量方式(通過JSON來創建對象)。

對象字面量方式是創建自定義對象的首選模式,簡單方便。

 

 缺點:使用同一個接口創建很多對象,會產生大量的重復代碼。比如我想再創建一個person1對象,我就得把上面的代碼再重新寫一遍,改變不同的屬性值。

2.工廠模式。

由於在ECMAScript中無法創建類,開發人員就發明了一種函數,用函數來封裝以特定接口創建對象的細節,工廠模式非常直觀,將創建對象的過程抽象為一個函數,用函數封裝以特定接口創建對象的細節。如下所示:

 

 

通俗地講,工廠模式就是將創建對象的語句放在一個函數里,通過傳入參數來創建特定對象,最后返回創建的對象。函數createPerson()能夠根據接受到的參數來構建一個包含所有必要信息的Person對象。可以無數次的調用這個函數,而每次它都會返回一個包含2個屬性和一個方法的對象。
缺點:工廠模式雖然可以創建多個相似的對象,但卻不能解決對象標識的問題,即怎樣知道一個對象的類型。構造函數模式應運而生。

3、構造函數模式
構造函數模式是java語言創建對象的通用方式。兩種語言用構造函數創建對象的方式略有不同,注意區別。在JavaScript中沒有類的概念,函數即為一等公民,因此,不必顯式聲明某個類,直接創建構造函數即可,類的方法和屬性在構造函數中(或原型對象上)處理。使用構造函數模式將前面的例子重寫示例代碼如下:

 

 

細心的朋友一定發現了構造函數的函數名首字母是大寫的,而普通函數首字母則是小寫,這是眾多OO語言約定俗成的規定,雖然大多數情況下不大寫也不會報錯,但是為了代碼的規范性和可讀性,還是應該將構造函數的首字母大寫,與普通函數區別開。
與工廠模式相比,用構造模式創建對象有以下幾點不同:

沒有顯示地創建對象
直接將屬性和方法賦給this對象
沒有return語句
此外,還應注意到要創建Person的實例,必須要使用new操作符,創建的實例對象將有一個constructor(構造器)屬性,指向Person構造函數。調用構造函數創建對象經過了以下幾個過程:
1.創建一個新對象
2.將構造函數的作用域賦給新對象(因此this就指向了這個新對象)
3.執行構造函數中的代碼
4.返回新對象(不需要顯式返回)
構造函數雖好用,但也不是沒有缺點。使用構造函數的主要問題是:每個方法都要在每個實例上創建一遍。在ECMAScript中,函數即對象,因此每定義一個函數,也就是實例化了一個對象。下面的例子證明了這個缺點。

 

 

也就是說通過構造函數實例化的多個對象的方法,是多個不同的方法,但它們內部的代碼以及實現的功能是相同的,這就造成了一定的資源浪費。
幸運的是,這個問題可以用原型模式來解決。

4、原型模式
js中,每個函數都有一個prototype屬性,它是一個指針,指向一個對象,叫做原型對象,原型對象包含了可以由特定類型的所有實例對象共享的屬性和方法。此外,這個對象有一個與生自來的屬性constructor,指向創建對象的構造方法。
使用原型模式可以讓所有的實例共享原型對象中的屬性和方法,也就是說,不必再構造函數中定義對象實例的信息。用代碼表示如下:

 

 了解過原型后,可以繼續在實例對象上增添屬性或方法:

 

 

當要讀取某個對象的屬性時,都會執行一次搜索,搜索首先從對象實例本身開始,如果在實例中找到了這個屬性,則搜索結束,返回實例屬性的值;
若實例上沒有找到,則繼續向對象的原型對象延伸,搜索對象的原型對象,若在原型對象上找到了,則返回原型上相應屬性的值,若沒有找到,則返回undefined。
因此,實例對象屬性會覆蓋原型對象上的同名屬性,所以上面第二行代碼輸出的是John。
Object.getPrototypeOf(object) 方法返回參數對象的原型對象。
Object.keys(object) 方法返回對象上課枚舉的實例屬性

原型模式也不是沒有缺點。首先,它省略了為構造函數傳遞初始化參數這一環節,結果所有實例在默認情況下都將取得相同的屬性值。雖然這會在某種程度上帶來一些不方便,但還不是原型的最大問題。原型模式的最大問題是由共享的本性所導致的。
原型中所有屬性是被很多實例共享的,這種共享對於函數非常合適。對於那些包含基本值的屬性倒也說的過去,通過在實例上添加一個同名屬性,可以隱藏原型中的對應屬性。然后,對於包含引用類型的屬性來說,問題就比較突出了。

 

 

問題來了,我們只想改變p5的朋友列表,但由於原型模式的共享本質,p6的朋友列表也隨之改變了。
因此,很少單獨使用原型模式。

5、組合使用構造函數模式和原型模式
組合使用構造函數模式和原型模式,是創建自定義類型的最常見方式。構造函數模式用於定義實例屬性,而原型模式用於定義方法和共享的屬性。結果,每個實例都會有自己的一份實例屬性的副本,但同時又共享着對方法的引用,最大限度的節省了內存。

 

 

在上面的例子中,實例屬性都是在構造函數中定義的,而由所有實例共享的屬性constructor和方法getName()則是在原型中定義的。而修改了p1.friends(向其中添加一個新字符串),並不會影響到p2.friends,因為他們分別引用了不同的數組。

其他模式
動態原型模式:僅在第一次調用構造函數時,將方法賦給原型對象的相應屬性,其他示例的處理方式同構造函數模式
寄生構造函數模式:僅僅封裝創建對象的代碼,然后再返回新創建的對象,仍使用new操作符調用
穩妥構造函數模式:沒有公共屬性,只有私有變量和方法,以及一些get/set方法,用以處理私有變量。

結語
每種模式都有各自的優缺點,具體要使用哪種,還需結合實際場景,深入理解,靈活運用。
參考鏈接:https://blog.csdn.net/samarket/article/details/89330519


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM