標籤:return 指定 基本 span eof 物件導向 工廠 最大 常用
ECMA把對象定義為:無序屬性的集合,其屬性可以包含基本值、對象或者函數。
1. 使用Object建構函式建立對象
建立自訂對象的最簡單的方式就是建立一個Object的執行個體,然後再為它添加屬性和方法。
//通過Object建構函式的執行個體建立對象var person = new Object();//添加屬性和方法person.name = "guo";person.age = ‘24‘;person.sayName = function(){ console.log(this.name);};//訪問屬性的兩種方式:點標記法和方括弧標記法console.log(person.name); //"guo"console.log(person[‘age‘]); //24person.sayName(); //"guo"
2. 使用對象字面量建立一個對象
//使用對象字面量建立一個對象var person = { name : "guo", age : 24, sayName : function(){ console.log(this.name); }};console.log(person.name); //"guo"console.log(person[‘age‘]); //24person.sayName(); //"guo"
3.原廠模式
雖然Object建構函式或者對象字面量都可以用來建立單個對象,但這些方式有個明顯的缺點:使用同一個介面建立對象,會產生大量的重複代碼。為瞭解決這個問題,提出原廠模式。
//使用原廠模式建立對象,返回帶有屬性和方法的person對象function createPerson(name, age){ var o = new Object(); o.name = name; o.age = age; o.sayName = function(){ console.log(this.name); }; return o;}var person1 = createPerson("guo", 24);person1.sayName(); //"guo"
4.使用自訂建構函式模式建立對象
// 使用自訂建構函式模式建立對象(作為建構函式的函數首字母要大寫,以區別其它函數)function Person(name,age){ this.name=name; this.age=age; this.sayName=function(){ console.log(this.name); };}var person1 = new Person("guo", 24);person1.sayName(); //"guo”
拓展:要建立Person的新執行個體,必須使用new操作符。那麼,new操作符具體幹了些什麼呢?
(1)建立一個新(空)對象
(2)將建構函式的範圍賦給新對象(因為this就指向了這個新對象)
(3)執行建構函式中的代碼(為這個新對象添加屬性)
(4)返回新對象
建構函式和其他函數的唯一區別:就在於調用它們的方式不同。任何函數,只要通過new操作符來調用,那它就可以作為建構函式;而任何函數,如果不通過new操作符來調用,那它跟普通函數也不會有什麼區別。這種方式有個缺陷是,上面例子中,sayName這個方法,它的每個執行個體都是指向不同的函數執行個體,而不是同一個。即不同執行個體上的同門函數是不相等的。
為瞭解決這個問題,提出了原型模式建立對象。
5.使用原型模式建立對象
//使用原型模式建立對象(解決了建構函式中的函數無法複用問題)function Person(){}Person.prototype = { //對象字面量文法 重寫原型對象 constructor : Person, name : "guo", age : 24, friends:["liu","li"], sayName:function(){ console.log(this.name); }};//建立執行個體1var person1 = new Person();person1.friends.push("yang"); console.log(person1.friends); //[ ‘liu‘, ‘li‘, ‘yang‘ ]//建立執行個體2var person2 = new Person(); console.log(person2.friends); //[ ‘liu‘, ‘li‘, ‘yang‘ ] //原型模式的缺陷person1.sayName(); //"guo"person2.sayName(); //"guo"
這裡我們發現了一個問題,而是原型模式的缺陷,上面例子中,person1改變數組的值,直接影響了person2中friends數組的值,這是我們不希望看到的。
原型模式最大的問題是由共用的本質所導致的,原型中所有的屬性是被所有執行個體共用的。對於參考型別的值,也出現了執行個體共用問題。
為瞭解決這個問題,提出了組合使用原型模式和建構函式建立對象。
6.組合使用建構函式和原型模式建立對象
顧名思義,建構函式用於定義執行個體屬性,而原型模式用於定義方法和共用的屬性。
//組合使用原型模式和建構函式建立對象(使用最廣泛、認同度最高)//建構函式用於定義執行個體屬性,而原型模式用於定義方法和共用的屬性function Person(name,age){ this.name = name; this.age = age; this.friends = ["liu","li"];}Person.prototype = { constructor : Person, sayName : function(){ console.log(this.name); }}var person1 = new Person("guo", 24);var person2 = new Person("zhu", 30);person1.friends.push("yang");console.log(person1.friends); //[ ‘liu‘, ‘li‘, ‘yang‘ ]console.log(person2.friends); //[ ‘liu‘, ‘li‘ ]person1.sayName();//"guo"person2.sayName();//"zhu"
7.動態原型模式
//動態原型模式(具有更好的封裝性)function Person(name, age){ //屬性 this.name = name; this.age = age; this.friends = ["liu","li"]; //方法 if(typeof this.sayName !="function"){ Person.prototype.sayName=function(){ console.log(this.name); }; }}var person1 = new Person("guo", 24);console.log(person1.friends); //[ ‘liu‘, ‘li‘ ]person1.sayName(); //"guo"
另外還有兩個建立對象的方法,寄生建構函式模式和穩妥建構函式模式。由於這兩個函數不是特別常用,這裡就不給出具體代碼了。有興趣可以查看 js高程P160-162
總結
ECMAScript 支援物件導向(OO)編程,但不使用類或者介面。對象可以在代碼執行過程中建立和增強,因此具有動態性而非嚴格定義的實體。在沒有類的情況下,可以採用下列模式建立對象。
(1)原廠模式,使用簡單的函數建立對象,為對象添加屬性和方法,然後返回對象。這個模式後來被建構函式模式所取代。
(2)建構函式模式,可以建立自訂參考型別,可以像建立內建對象執行個體一樣使用new 操作符。不過,建構函式模式也有缺點,即它的每個成員都無法得到複用,包括函數。由於函數可以不局限於任何對象(即與對象具有鬆散耦合的特點),因此沒有理由不在多個對象間共用函數。
(3)原型模式,使用建構函式的prototype 屬性來指定那些應該共用的屬性和方法。組合使用建構函式模式和原型模式時,使用建構函式定義執行個體屬性,而使用原型定義共用的屬性和方法。
JavaScript建立對象的幾種方式總結