JavaScript 創建對象的七種方式
JavaScript創建對象的方式有很多,通過Object構造函數或對象字面量的方式也可以創建單個對象,顯然這兩種方式會產生大量的重複代碼,並不適合量產。接下來介紹七種非常經典的創建對象的方式,他們也各有優缺點。
工廠模式
function createPerson(name, job) { var o = new Object() o.name = name o.job = job o.sayName = function() { console.log(this.name) } return o }var person1 = createPerson("Jiang", "student")var person2 = createPerson("X", "Doctor")
可以無數次調用這個工廠函數,每次都會返回一個包含兩個屬性和一個方法的對象
工廠模式雖然解決了創建多個相似對象的問題,但是沒有解決對象識別問題,即不能知道一個對象的類型
構造函數模式
function Person(name, job) { this.name = name this.job = job this.sayName = function() { console.log(this.name) } }var person1 = new Person("Jiang", "student")var person2 = new Person("X", "Doctor")
沒有顯示的創建對象,使用new來調用這個構造函數,使用new後會自動執行如下操作
創建一個新對象
這個新對象會被執行[[prototype]]鏈接
這個新對象會綁定到函數調用的this
返回這個對象
使用這個方式創建對象可以檢測對象類型
person1 instanceof Object // trueperson1 instanceof Person //true
但是使用構造函數創建對象,每個方法都要在每個實例上重新創建一次
原型模式
將信息直接添加到原型對象上。使用原型的好處是可以讓所有的實例對象共享它所包含的屬性和方法,不必在構造函數中定義對象實例信息。
原型是一個非常重要的概念,在 一篇文章看懂 proto 和prototype的關係及區別 中講的非常詳細
更簡單的寫法
function Person() { } Person.prototype = { name: "jiang", job: "student", sayName: function() { console.log(this.name) } }var person1 = new Person()
將Person.prototype設置為等於一個以對象字面量形式創建的對象,但是會導致 .constructor 不在指向Person了。
使用這種方式,完全重寫了默認的Person.prototype對象,因此 .constructor 也不會存在這裡
Person.prototype.constructor === Person // false
如果需要這個屬性的話,可以手動添加
function Person() { } Person.prototype = { constructor:Person name: "jiang", job: "student", sayName: function() { console.log(this.name) } }
不過這種方式還是不夠好,應為constructor屬性默認是不可枚舉的,這樣直接設置,它將是可枚舉的。所以可以時候,Object.defineProperty方法
Object.defineProperty(Person.prototype, "constructor", { enumerable: false, value: Person })
缺點
使用原型,所有的屬性都將被共享,這是個很大的優點,同樣會帶來一些缺點
原型中所有屬性實例是被很多實例共享的,這種共享對於函數非常合適。對於那些包含基本值的屬性也勉強可以,畢竟實例屬性可以屏蔽原型屬性。但是引用類型值,就會出現問題了
function Person() { } Person.prototype = { name: "jiang", friends: ["Shelby", "Court"] }var person1 = new Person()var person2 = new Person() person1.friends.push("Van")console.log(person1.friends) //["Shelby", "Court", "Van"]console.log(person2.friends) //["Shelby", "Court", "Van"]console.log(person1.friends === person2.friends) // true
friends存在與原型中,實例person1和person2指向同一個原型,person1修改了引用的數組,也會反應到實例person2中
組合使用構造函數模式和原型模式
這是使用最為廣泛、認同度最高的一種創建自定義類型的方法。它可以解決上面那些模式的缺點
使用此模式可以讓每個實例都會有自己的一份實例屬性副本,但同時又共享著對方法的引用
這樣的話,即使實例屬性修改引用類型的值,也不會影響其他實例的屬性值了
function Person(name) { this.name = name this.friends = ["Shelby", "Court"] } Person.prototype.sayName = function() { console.log(this.name) }var person1 = new Person()var person2 = new Person() person1.friends.push("Van")console.log(person1.friends) //["Shelby", "Court", "Van"]console.log(person2.friends) // ["Shelby", "Court"]console.log(person1.friends === person2.friends) //false
動態原型模式
動態原型模式將所有信息都封裝在了構造函數中,初始化的時候,通過檢測某個應該存在的方法時候有效,來決定是否需要初始化原型
function Person(name, job) { // 屬性 this.name = name this.job = job // 方法 if(typeof this.sayName !== "function") { Person.prototype.sayName = function() { console.log(this.name) } } }var person1 = new Person("Jiang", "Student") person1.sayName()
只有在sayName方法不存在的時候,才會將它添加到原型中。這段代碼只會初次調用構造函數的時候才會執行。
此後原型已經完成初始化,不需要在做什麼修改了
這裡對原型所做的修改,能夠立即在所有實例中得到反映
其次,if語句檢查的可以是初始化之後應該存在的任何屬性或方法,所以不必用一大堆的if語句檢查每一個屬性和方法,只要檢查一個就行
寄生構造函數模式
這種模式的基本思想就是創建一個函數,該函數的作用僅僅是封裝創建對象的代碼,然後再返回新建的對象
function Person(name, job) { var o = new Object() o.name = name o.job = job o.sayName = function() { console.log(this.name) } return o }var person1 = new Person("Jiang", "student") person1.sayName()
這個模式,除了使用new操作符並把使用的包裝函數叫做構造函數之外,和工廠模式幾乎一樣
構造函數如果不返回對象,默認也會返回一個新的對象,通過在構造函數的末尾添加一個return語句,可以重寫調用構造函數時返回的值
穩妥構造函數模式
首先明白穩妥對象指的是沒有公共屬性,而且其方法也不引用this。
穩妥對象最適合在一些安全環境中(這些環境會禁止使用this和new),或防止數據被其他應用程序改動時使用
穩妥構造函數模式和寄生模式類似,有兩點不同:一是創建對象的實例方法不引用this,而是不使用new操作符調用構造函數
function Person(name, job) { var o = new Object() o.name = name o.job = job o.sayName = function() { console.log(name) } return o }var person1 = Person("Jiang", "student") person1.sayName()
和寄生構造函數模式一樣,這樣創建出來的對象與構造函數之間沒有什麼關係,instanceof操作符對他們沒有意義
想要系統學習web前端和免費學習資料的 可以加裙六二三九六六八零六
※C語言之地雷遊戲,有什麼問題么
※分享史上java最牛逼,最簡短的代碼
※python之隨機森林演算法入門
TAG:IT技術java交流 |
※塗鴉的正確打開方式!Michel Basquiat
※Affiliate Marketing聯盟營銷的正確打開方式
※白鷺引擎發布 調整Facebook Instant Games 接入方式
※3.15 World Consumer Rights Day|有品質的娛樂方式,從不聲張
※spring註解方式與AspectJ框架資料庫事務
※抄襲Margiela設計+潮牌營銷方式=紅牌Vetements?
※Supreme x The North Face雪山外套再出新款!入手方式一併告訴你!
※Ultra Violet紫外光的正確打開方式
※Struts2框架獲取Servlet API之注入方式詳解
※Curr Microbiol:不同處理方式的植體表面菌膜的形成
※Windows VS Linux,你更青睞的哪種桌面運行方式?
※Linux軟連接文件:類似於Windows的快捷方式!
※Reddit據稱取消比特幣支付方式,或因Coinbase更換商戶服務
※用雕塑的方式創造出腦海中的奇幻樂園 | 一位自學成才的3D藝術家Alexei Popovici
※Dominik Schiener談數據的價值和未來的數據處理方式
※三星Galaxy S9/S9 Plus的6種截圖方式
※PowerShell設置右鍵快捷方式
※Angelababy和王子文,酷女孩的兩種打開方式
※Music Fashion Show,這應該是春夏時裝秀的最酷打開方式了!
※瑜伽鴿子式Pigeon Pose的 3 種練習方式