JavaScript 建構函式(Constructor)也稱為構造器、型別函數,功能類似物件模板,一個建構函式可以生成任意多個範例,範例物件具有相同的屬性、行為特徵,但不相等。
定義建構函式
在語法和用法上,建構函式與普通函數沒有任何區別。定義建構函式的方法如下:
function 型別名稱 (設定引數) {
this.屬性1 = 屬性值1;
this.屬性2 = 屬性值2;
...
this.方法1 = function () {
//處理程式碼
};
...
//其他程式碼,可以包含return語句
}
建議建構函式的名稱首字母大寫,以便與普通函數進行區分。
建構函式有兩個顯著特點。
-
函數體內使用 this,參照將要生成的範例物件。
-
必需使用 new 命令呼叫函數,生成範例物件。
範例
下面範例演示定義一個建構函式,包含了兩個屬性和一個方法。
function Point (x, y) { //建構函式
this.x = x; //私有屬性
this.y = y; //私有屬性
this.sum = function () { //方法
return this.x + this.y;
}
}
在上面程式碼中,Point 就是建構函式,它提供模板,用來生成範例物件。
呼叫建構函式
使用 new 命令可以呼叫建構函式,建立範例,並返回這個物件。
範例
下面使用 new 命令呼叫建構函式,生成兩個範例,然後分別讀取屬性,呼叫方法 sum()。
function Point (x, y) { //建構函式
this.x = x; //私有屬性
this.y = y; //私有屬性
this.sum = function () { //私有方法
return this.x +this.y;
}
}
var p1 = new Point(100, 200); //範例化物件1
var p2 = new Point(300, 400); //範例化物件2
console.log(p1.x); //100
console.log(p2.x); //300
console.log(p1.sum()); //300
console.log(p2.sum()); //700
函數構造可以接收引數,以便初始化範例物件。如果不需要傳遞引數,可以省略小括號,直接使用 new 命令斯奧用,下面兩行程式碼是等價的。
var p1 = new Point();
var p2 = new Point;
如果不使用 new 命令,直接使用小括號呼叫建構函式,這時建構函式就是普通函數,不會生成範例物件,this 就代表呼叫函數的物件,在用戶端指代全域性物件 window。
為了避免誤用,最有效的方法是在函數中啟用嚴格模式。程式碼如下。
function Point (x, y) { //建構函式
'use strict'; //啟用嚴格模式
this.x = x; //私有屬性
this.y = y; //私有屬性
this.sum = function () { //私有方法
return this.x + this.y;
}
}
這樣呼叫建構函式時,必須使用 new 命令,否則將丟擲異常。
或者使用 if 對 this 進行檢測,如果 this 不是範例物件,則強迫返回範例物件。
function Point(x, y) { //建構函式
if (! (this instanceof Point)) return new Point(x, y); //檢測this是否為範例物件
this.x = x; //私有屬性
this.y = y; //私有屬性
this.sum = function () { //私有方法
return this.x + this.y;
}
}
建構函式的返回值
建構函式執行使用 return 語句。如果返回值為簡單值,則將被忽略,直接返回 this 指代的範例物件;如果返回值為物件,則將覆蓋 this 指代的範例,返回 return 後面跟隨的物件。
為什麼會出現這種情況?這與 new 命令解析過程有關係,使用 new 命令呼叫函數的解析過程如下:
-
當使用 new 命令呼叫函數時,先建立一個空物件,作為範例返回。
-
設定範例的原型,指向建構函式的 prototype 屬性。
-
設定建構函式體內的 this 值,讓它指向範例。
-
開始執行建構函式內部的程式碼。
-
如果建構函式內部有 return 語句,而且 return 後面跟著一個物件,會返回 return 語句指定的物件;否則會忽略 return 返回值,直接返回 this 物件。
範例
下面範例在建構函式內部定義 return 返回一個物件直接量,當使用 new 命令呼叫建構函式時,返回的不是 this 指代的範例,而是這個物件直接量,因此當讀取 x 和 y 屬性值時,與預期的結果是不同的。
function Point (x, y) { //建構函式
this.x = x; //私有屬性
this.y = y; //私有屬性
return {x : true, y : false}
}
var p1 = new Point(100, 200); //範例化物件1
console.log(p1.x); //true
console.log(p1.y); //false
參照建構函式
在普通函數內,使用 arguments.callee 可以參照函數自身。如果在嚴格模式下,是不允許使用 arguments.cellee 參照函數的,這時可以使用 new.target 來存取建構函式。
範例
function Point (x, y) { //建構函式
'use strict'; //啟用嚴格模式
if (! (this instanceof new.target)) return new new.target(x, y); //檢測this是否為範例物件
this.x = x; //私有屬性
this.y = y; //私有屬性
}
var p1 = new Point(100, 200); //範例化物件1
console.log(p1.x); //100
IE 瀏覽器對其支援不是很完善,使用時要考慮相容性。