這篇文章帶給大家的內容是關於JavaScript中創建物件方式的總結(超經典) ,有一定的參考價值,有需要的朋友可以參考一下,希望對你有所幫助。
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) } return o } var person1 = Person('Mike', 'student') person1.sayName()
和寄生构造函数模式一样,这样创建出来的对象与构造函数之间没有什么关系,instanceof操作符对他们没有意义
相关推荐:
以上是JavaScript中建立物件方式的總結(超經典)的詳細內容。更多資訊請關注PHP中文網其他相關文章!