Object建構函式和物件字面量都可以用來建立單個物件,但是在建立多個物件時,會產生大量重複程式碼.
1.工廠模式
工廠模式抽象了建立具體物件的過程.由於ECMAScript無法建立類,我們用函式來封裝以特定介面建立物件的細節.
function createPerson(name, age, job) {
var o = new Object();
o.name = name;
o.age = age;
o.job = job;
o.sayName = function() {
console.log(this.name);
}
return o;
}
// 根據接收到的引數,構建一個包含三個屬性一個方法的物件,並返回
var person1 = createPerson("zhu", 26, "FE");
ps. 工廠模式解決了建立多個相似物件的問題,卻無法識別物件(物件的型別)
2.建構函式模式
用來建立特定型別的物件,比如Object/Array這樣的原生建構函式,或者自定義建構函式(可以自定義物件型別的屬性和方法).
/* 1.沒有顯示建立物件
* 2.直接將屬性和方法賦值給this物件
* 3.沒有return語句
* 4.首字母大寫(區別於ECMAScript中其他函式,建構函式本身也是函式,只不過可以建立物件)
*/
function Person(name, age, job) {
this.name = name;
this.age = age;
this.job = job;
this.sayName = function() {
console.log(this.name);
}
}
// 必須使用new操作符
var person1 = new Person("zhu", 26, "FE");
var person2 = new Person("liu", 23, "JAVA");
2.1 呼叫該總種建構函式會經歷四個步驟
- 建立一個新物件
- 將建構函式的作用域賦給新物件(因此this就指向了這個新物件)
- 執行建構函式中的程式碼(為這個新物件新增屬性)
- 返回新物件
2.2 物件型別
- person1,person2分別儲存著Person的一個不同例項,兩個物件都有constructor(建構函式)屬性指向Person.
js person1.constructor == Person, person2.constructor == Person // true
person1,person2既是Object例項也是Person例項.
// 所有物件均繼承自Object person1 instanceof Object, person1 instanceof Person // true person2 instanceof Object, person2 instanceof Person // true
ps. 建立自定義建構函式意味著可以將它的例項標識為一種特定的型別.
2.3 將建構函式當作函式
建構函式與普通函式的區別在於呼叫它們的方式不同,只要通過new操作符呼叫,它就可以作為建構函式.
// 當作建構函式使用,使用new操作符來建立一個新物件.
var person = new Person("zhu", 26, "FE");
person.sayName();
// 作為普通函式呼叫,屬性和方法都被新增到window物件.
// 在全域性作用域中呼叫一個函式時,this物件總是指向Global物件(在瀏覽器中就是window物件)
Person("zhu", 26, "FE");
window.sayName();
// 使用call()或者apply()在某個特定物件的作用域中呼叫
var o = new Object();
Person.call(o, "zhu", 26, "FE");
o.sayName();
ps. 建構函式模式定義的建構函式是定義在Global物件中的.
2.4 建構函式的問題
每個方法都要在每個例項上重新建立一遍,person1和person2的同名sayName方法不是同一個function的例項.
ps. ECMAScript的函式是物件,因此每定義一個函式,也就例項化一個物件.即每個Person例項都包含一個不同function例項.
// 邏輯上的建構函式可以這樣定義
function Person(name, age) {
this.name = name;
this.age = age;
this.sayName = new function() {
console.log(this.name);
}
}
沒有必要建立兩個完成同樣任務的function例項,然而將sayName提到全域性雖然解決做同一件事的問題,但是實際上只能被某個物件呼叫,而且可能需要定義很多全域性函式(無封裝性).