建構函式
JavaScript 中的建構函式和其它語言中的建構函式是不同的。
通過 new 關鍵字方式調用的函數都被認為是建構函式。
在建構函式內部 - 也就是被調用的函數內 - this 指向新建立的對象 Object。
這個新建立的對象的 prototype 被指向到建構函式的 prototype。
如果被調用的函數沒有顯式的 return 運算式,則隱式的會返回 this 對象 - 也就是新建立的對象。
function Foo() {
this.bla = 1;
}
Foo.prototype.test = function() {
console.log(this.bla);
};
var test = new Foo();
上面代碼把 Foo 作為建構函式調用,並設定新建立對象的 prototype 為 Foo.prototype。
顯式的 return 運算式將會影響返回結果,但僅限於返回的是一個對象。
function Bar() {
return 2;
}
new Bar(); // 返回新建立的對象
function Test() {
this.value = 2;
return {
foo: 1
};
}
new Test(); // 返回的對象
new Bar() 返回的是新建立的對象,而不是數位字面值 2。
因此 new Bar().constructor === Bar,但是如果返回的是數字對象,結果就不同了,如下所示
function Bar() {
return new Number(2);
}
new Bar().constructor === Number
這裡得到的 new Test()是函數返回的對象,而不是通過new關鍵字新建立的對象,因此:
(new Test()).value === undefined
(new Test()).foo === 1
如果 new 被遺漏了,則函數不會返回新建立的對象。
function Foo() {
this.bla = 1; // 擷取設定全域參數
}
Foo(); // undefined
雖然上例在有些情況下也能正常運行,但是由於 JavaScript 中 this 的工作原理,
這裡的 this 指向全域對象。
原廠模式
為了不使用 new 關鍵字,建構函式必須顯式的返回一個值。
function Bar() {
var value = 1;
return {
method: function() {
return value;
}
}
}
Bar.prototype = {
foo: function() {}
};
new Bar();
Bar();
上面兩種對 Bar 函數的調用返回的值完全相同,一個新建立的擁有 method 屬性的對象被返回,
其實這裡建立了一個閉包。
還需要注意, new Bar() 並不會改變返回對象的原型(譯者註:也就是返回對象的原型不會指向 Bar.prototype)。
因為建構函式的原型會被指向到剛剛建立的新對象,而這裡的 Bar 沒有把這個新對象返回(譯者註:而是返回了一個包含 method 屬性的自訂對象)。
在上面的例子中,使用或者不使用 new 關鍵字沒有功能性的區別。
上面兩種方式建立的對象不能訪問 Bar 原型鏈上的屬性,如下所示:
var bar1 = new Bar();
typeof(bar1.method); // "function"
typeof(bar1.foo); // "undefined"
var bar2 = Bar();
typeof(bar2.method); // "function"