摘要:創建對象的方式有很多,通過構造函數或對象字面量的方式也可以創建單個對象,顯然這兩種方式會產生大量的重復代碼,并不適合量產。四組合使用構造函數模式和原型模式組合使用構造函數模式和原型模式是使用最為廣泛認同度最高的一種創建自定義類型的方法。
JavaScript創建對象的方式有很多,通過Object構造函數或對象字面量的方式也可以創建單個對象,顯然這兩種方式會產生大量的重復代碼,并不適合量產。接下來介紹七種非常經典的創建對象的方式,他們也各有優缺點。(內容主要來自于《JavaScript高級程序設計》,還參考了一下別人寫的文章)
一、工廠模式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("Mike", "student") var person2 = createPerson("X", "engineer")
可以無數次調用這個工廠函數,每次都會返回一個包含兩個屬性和一個方法的對象。
工廠模式雖然解決了創建多個相似對象的問題,但是沒有解決對象識別問題,即不能知道一個對象的類型。
function Person(name, job) { this.name = name; this.job = job; this.sayName = function() { console.log(this.name); } } var person1 = new Person("Mike", "student") var person2 = new Person("X", "engineer")
沒有顯示的創建對象,使用new來調用這個構造函數,使用new后會自動執行如下操作:
①創建一個新對象;
②將構造函數的作用域賦給新對象(因此this就指向了這個新對象);
③執行構造函數中的代碼(為這個新對象添加屬性);
④返回新對象。
缺點:每個方法都要在每個實例上重新創建一遍。
創建兩個完成同樣任務的的Function實例的確沒有必要。況且有this對象在,根本不用在執行代碼前就把函數綁定到特定的對象上,可以通過這樣的形式定義:
function Person( name, age, job ){ this.name = name; this.age = age; this.job = job; this.sayName = sayName; } function sayName(){ alert( this.name ); }
如此一來,就可以將sayName()函數的定義轉移到構造函數外部。而在構造函數內部,我們將sayName屬性設置成全局的sayName函數。這樣的話,由于sayName包含的是一個指向函數的指針,因此person1和person2對象就可以共享在全局作用域中定義的同一個sayName()函數。
這樣做解決了兩個函數做同一件事的問題,但是新的問題又來了:在全局作用域中定義的函數實際上只能被某個對象調用,這讓全局作用域有點名不副實。而更重要的是:如果對象需要定義很多方法,那么就需要定義很多個全局函數,這樣一來,我們自定義的這個引用類型就毫無封裝性可言了。
這些問題可以通過使用原型模式來解決。
三、原型模式function Person() { } Person.prototype.name = "Mike" Person.prototype.job = "student" Person.prototype.sayName = function() { console.log(this.name) } var person1 = new Person()
將信息直接添加到原型對象上。使用原型的好處是可以讓所有的實例對象共享它所包含的屬性和方法,不必在構造函數中定義對象實例信息,而是可以將這些信息直接添加到原型對象中。
①理解原型
無論什么時候,只要創建了一個新函數,就會根據一組特定的規則為該函數創建一個prototype屬性。
在默認情況下,所有prototype屬性都會自動獲得一個constructor(構造函數)屬性,這個屬性包含一個指向prototype屬性所在函數的指針。
每當代碼讀取某個對象的某個屬性時,都會執行一搜索,目標是具有給定名字的屬性。搜索首先從對象實例本身開始。如果在實例中找到了具有給定名字的屬性,則返回該屬性的值;如果沒有找到,則繼續搜索指針指向的原型對象,在原型對象中查找具有給定名字的屬性。如果在原型對象中找到了這個屬性,則返回該屬性的值。
雖然可以通過對象實例訪問保存在原型中的值,但卻不能通過對象實例重寫原型中的值。
如果我們在實例中添加了一個屬性,而該屬性與實例中的一個屬性同名,那么就會在實例中創建該屬性,該屬性將會屏蔽原型中的那個屬性。
即使是將屬性設置為null,也只是在實例中的屬性值為null。
不過,使用delete操作符可以完全刪除實例屬性,從而能夠重新訪問原型中的屬性。
使用hasOwnProperty() 方法可以檢測一個屬性是存在于實例中,還是存在與原型中。這個方法只在給定屬性存在于對象實例中時,才會返回true。
②原型與in操作符
in操作符會在通過對象能夠訪問給定屬性時返回true,無論該屬性是存在于實例中還是原型中。
③更簡單的原型語法
function Person(){ } Person.prototype = { name : "Mike", age : 29, job : "engineer", syaName : function(){ alert( this.name ); } };
//在上面的代碼中,將Person.prototype設置為等于一個以對象字面量形式創建的新對象。最終結果相同,但有一個例外:constructor屬性不再指向Person。
四、組合使用構造函數模式和原型模式組合使用構造函數模式和原型模式是使用最為廣泛、認同度最高的一種創建自定義類型的方法。它可以解決上面那些模式的缺點,使用此模式可以讓每個實例都會有自己的一份實例屬性副本,但同時又共享著對方法的引用,這樣的話,即使實例屬性修改引用類型的值,也不會影響其他實例的屬性值了。還支持向構造函數傳遞參數,可謂是集兩種模式的優點。
function Person(name) { this.name = name; this.friends = ["Jack", "Merry"]; } Person.prototype.sayName = function() { console.log(this.name); } var person1 = new Person(); var person2 = new Person(); person1.friends.push("Van"); console.log(person1.friends) //["Jack", "Merry", "Van"] console.log(person2.friends) // ["Jack", "Merry"] 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("Mike", "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("Mike", "student") person1.sayName()
這個模式,除了使用new操作符并把使用的包裝函數叫做構造函數之外,和工廠模式幾乎一樣。
構造函數如果不返回對象,默認也會返回一個新的對象,通過在構造函數的末尾添加一個return語句,可以重寫調用構造函數時返回的值。
首先明白穩妥對象指的是沒有公共屬性,而且其方法也不引用this。穩妥對象最適合在一些安全環境中(這些環境會禁止使用this和new),或防止數據被其他應用程序改動時使用。
穩妥構造函數模式和寄生模式類似,有兩點不同:1.是創建對象的實例方法不引用this;2.不使用new操作符調用構造函數
function Person(name, job) { var o = new Object(); o.name = name; o.job = job; o.sayName = function() { console.log(name) //注意這里沒有了"this"; } return o } var person1 = Person("Mike", "student") person1.sayName();
和寄生構造函數模式一樣,這樣創建出來的對象與構造函數之間沒有什么關系,instanceof操作符對他們沒有意義
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/97052.html
摘要:在使用字面量表示法的時候,并不會調用對象的構造函數種常用方法同一樣可通過和字面量兩種方法來創建。直接調用基本包裝類型的構造函數,返回實例都屬于這個構造函數是會根據參數返回相應的基本包裝類型的實例。 第五章、引用類型 一共七種引用類型: Object: 可通過new和字面量兩種方法來創建。在使用字面量表示法的時候,并不會調用對象的構造函數 Array: 17種常用方法; 同object...
摘要:高度模型淺識為的簡寫,簡稱為塊級格式化上下文,為瀏覽器渲染某一區域的機制,中只有和中還增加了和。并非所有的布局都會在開發中使用,但是其中也會涉及一些知識點。然而在不同的純制作各種圖形純制作各種圖形多圖預警 一勞永逸的搞定 flex 布局 尋根溯源話布局 一切都始于這樣一個問題:怎樣通過 CSS 簡單而優雅的實現水平、垂直同時居中。記得剛開始學習 CSS 的時候,看到 float 屬性不...
閱讀 3512·2021-11-15 11:38
閱讀 825·2021-11-08 13:27
閱讀 2235·2021-07-29 14:50
閱讀 2970·2019-08-29 13:06
閱讀 838·2019-08-29 11:22
閱讀 2408·2019-08-29 11:04
閱讀 3499·2019-08-28 18:23
閱讀 890·2019-08-26 13:46