相關推薦:《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')
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操作符对他们没有意义
更多编程相关知识,请访问:编程学习!!
以上是JavaScript中創建物件的7種經典方式(總結)的詳細內容。更多資訊請關注PHP中文網其他相關文章!