一、單個對象
創建單個對象時,可以採用對象字面量{}或者new+object構造函數來創建;
var person1 = new Object(); //person1是由new+object構造函數創建
person1.name = 'ermiao';
person1.age = 18;
var person2 = { //person2是由對象字面量{}創建
name:'Ermiao',
age: 18
}
二、多個對象
創建多個對象時,相似的對象若每個都要單獨創建,會產生重複的代碼,因此採用以下方法:
1.工廠模式
工廠模式是抽象出創建對象過程中的重複步驟,並用一個函數封裝起來的模式
function createPerson(name,age){
var p = new Object();
p.name = name;
p.age = age;
p.say = function(){
alert(this.name);
}
return p
}
var person1 = createPerson('ermiao',18);
優點:解決了創建多個相似對象的問題
缺點:無法判斷對象的類型
2.構造函數模式
除了採用自帶的Object構造函數,還可以創建自定義構造函數
function Person(name,age){ //創建自定義的構造函數
this.name = name;
this.age = age;
this.say = function(){
alert(this.name);
}
}
var person1 = new Person('ermiao',18); //person1由new+自定義構造函數創建
var person2 = new Person('Ermiao',18); //person2由new+自定義構造函數創建
對比工廠模式,(自定義)構造函數模式不用顯示創建對象、不用返回對象、把對象的屬性值都賦給了this。
在JavaScript中,構造函數和普通函數的唯一區別是調用方式不同。按照慣例,構造函數名的首字母應大寫。
任何函數只要能夠被new調用就叫構造函數,不被new調用就是普通函數。如上例的Person函數,若不被new調用,就是普通函數,this指向全局變量window。
在用new+自定義構造函數生成實例時,經歷了以下步驟:
- 創建一個新對象
- 將構造函數的作用域賦給新對象
- 執行構造函數的代碼(添加屬性)
- 返回新對象
優點:通過自定義構造函數創建的實例可以標識爲特殊的類型(能夠判斷類型)。例如上例中person1和person2都是Person的實例,也都是Object的實例(繼承)
缺點:被同一構造函數創建的多個對象之間沒有聯繫。如上例person1和person2的say()函數是兩個不同的函數,完成相同任務的函數不必要創建兩遍並在執行前綁定在特定對象上。
3.原型模式
爲了增加同一構造函數創建的多個對象之間的聯繫,每個函數都有一個prototype(原型)屬性指向原型對象。原型對象包含特定類型的所有實例共享的屬性和方法(如上例的say方法只在原型對象定義一次,並由person1和person2共享)
關於原型對象的內容請看:一文看懂原型鏈
var Person = function(){}; //原型模式不定義構造函數,只定義原型對象中的共享屬性
Person.prototype = {
constructor: Person, //採用對象字面量給prototype賦值,一定要將constructor改成Person
name:'ermiao',
age:18,
say:function(){
alert(this.name);
}
};
優點:能夠使實例之間共享屬性和方法
缺點:若所有屬性都是共享不太方便,並且若共享屬性是引用類型的,則能夠同時更改可能導致錯誤
4.組合使用構造函數模式和原型模式
最常用的方法是組合使用構造函數和原型模式,由構造函數創建獨有屬性,由原型對象定義共享屬性。
var Person = function(name,age){ //構造函數模式
this.name = name;
this.age = age;
};
//採用對象字面量給prototype賦值,一定要將constructor改成Person
Person.prototype = { //原型模式
constructor: Person,
say:function(){
alert(this.name);
}
};
優點:既能定義實例屬性又能定義實例共享屬性
缺點:要定義兩次屬性(構造函數,原型對象)
5.動態原型模式
該模式是在構造函數中初始化原型對象屬性(必要情況下),只在初次調用構造函數時才執行。
var Person = function(name,age){
this.name = name;
this,age = age;
if(typeOf this.say != 'function'){ //此處也可用instanceOf判斷
Person.prototype.say = function(){
alert(this.name);
};
}
}
var person1 = new Person('ermiao',18);
person1.say(); //輸出'ermiao'
注意:使用動態原型模式不能用對象字面量來定義原型屬性,會改變原型的constructor屬性(指向object)
優點:保留構造函數和原型模式的優點,又封裝在一起
缺點:定義原型屬性時不能用對象字面量
6.寄生構造函數模式
該模式除了使用new操作符調用函數,其他和工廠模式是一樣的(效果一樣,寫法一樣)
//工廠模式定義函數
var Person = function(name,age){ //區別1:函數名按構造函數規則寫
var p = new Object();
p.name = name;
p.age = age;
p.say = function(
alert(this.name);
)
return p
};
var person1 = new Person('ermiao',18); //區別2:使用new操作符調用函數
注意:同工廠模式一樣,返回的對象和構造函數、構造函數的原型沒有任何關係。
當使用new操作符調用構造函數時,若構造函數中沒有返回值(return),則默認返回創建的實例;若構造函數中有返回值,則以返回值優先
優點:只是看起來比工廠模式更像創建對象(但實質和工廠模式一樣)
缺點:返回的對象和構造函數沒關係,不能判斷對象的特有類型,不建議使用該模式
7.穩妥構造函數模式
穩妥對象是指沒有公共屬性也不使用this的對象。
該模式不使用this和new,在函數中,只爲返回對象綁定方法,不綁定數據,傳入或內部定義的參數作爲私有變量只能由返回對象的方法調用。(相當於c++中類的私有變量)
function Person(name,age){
var p = new Object(); //創建返回對象
//定義私有變量
var para_name = name;
var para_age = age;
//定義返回對象的方法
p.sayName = function(){
alert(para_name);
};
p.sayAge = function(){
alert(para_age);
};
}
var person1 = Person('ermiao',18);
person1.sayName(); //輸出'ermiao'
person1.sayAge(); //輸出18
person1.name; //輸出undefined
優點:比較安全,不使用this和new,將所有數據成員私有化
缺點:不可以添加成員
注意:同工廠模式一樣,返回的對象和構造函數、構造函數的原型沒有任何關係。