ECMAScript 中的構造函數可用來創建特定類型的對象。像 Object 和 Array 這樣的原生構造函數,在運行時會自動出現在執行環境中。此外,也可以創建自定義的構造函數,從而定義自定義對象類型的屬性和方法。例如,可以使用構造函數模式將前面的《 使用工廠模式創建對象》例子重寫如下。
function Person(name, age, job){
this.name = name;
this.age = age;
this.job = job;
this.sayName = function(){
alert(this.name);
};
}
var person1 = new Person(“Nicholas”, 29, “Software Engineer”);
var person2 = new Person(“Greg”, 27, “Doctor”);
在這個例子中, Person() 函數取代了 createPerson() 函數。我們注意到,Person() 中的代碼除了與 createPerson() 中相同的部分外,還存在以下不同之處:
- 沒有顯式地創建對象;
- 直接將屬性和方法賦給了 this 對象;
- 沒有 return 語句。
此外,還應該注意到函數名 Person 使用的是大寫字母 P。按照慣例,構造函數始終都應該以一個大寫字母開頭,而非構造函數則應該以一個小寫字母開頭。這個做法借鑒自其他OO語言,主要是為了區別于 ECMAScript 中的其他函數;因為構造函數本身也是函數,只不過可以用來創建對象而已。
要創建 Person 的新實例,必須使用 new 操作符。以這種方式調用構造函數實際上會經歷以下4個步驟:
- 創建一個新對象;
- 將構造函數的作用域賦給新對象(因此 this 就指向了這個新對象);
- 執行構造函數中的代碼(為這個新對象添加屬性);
- 返回新對象。
在前面例子的最后, person1 和 person2 分別保存著 Person 的一個不同的實例。這兩個對象都有一個 constructor (構造函數)屬性,該屬性指向 Person ,如下所示。
alert(person1.constructor == Person); //true
alert(person2.constructor == Person); //true
對象的 constructor 屬性最初是用來標識對象類型的。但是,提到檢測對象類型,還是 instanceof 操作符要更可靠一些。我們在這個例子中創建的所有對象既是 Object 的實例,同時也是 Person 的實例,這一點通過 instanceof 操作符可以得到驗證。
alert(person1 instanceof Object); //true
alert(person1 instanceof Person); //true
alert(person2 instanceof Object); //true
alert(person2 instanceof Person); //true
創建自定義的構造函數意味著將來可以將它的實例標識為一種特定的類型;而這正是構造函數模式勝過工廠模式的地方。在這個例子中, person1 和 person2 之所以同時是 Object 的實例,是因為所有對象均繼承自 Object (詳細內容稍后討論)。