一般而言,在JavaScript中創建對象時需要使用關鍵字new,但是某些時候,開發者希望無論new關鍵字有沒有被顯式使用,構造函數都可以被正常調用,即構造函數同時還具備簡單工廠的職能。JavaScript的一個特性使得這樣的實現變得可行:如果構造函數中返回了對象,無論有沒有使用new關鍵字,最終返回的值都是函數return的值。
基於這點特性,本文介紹了四種實現方式,拋磚引玉,歡迎拍磚~
1. 在構造函數中返回對象字面量
function Person(name) {
return {
name: name,
getName: function () {
return this.name;
}
};
}
console.log(new Person('Ralph').getName()); //Ralph
console.log(Person('Ralph').getName()); //Ralph
缺點:
不方便控制prototype屬性,不利於高效擴展對象方法,instanceof操作符失效且constructor屬性丟失
2. 在構造函數中使用內部函數構造對象
function Person(name) {
// lazy loading,在Person函數第一次被調用時初始化內部函數_Person
if (!Person.inited) {
Person._Person = function (name) {
this.name = name;
};
// 可以利用prototype進行方法擴展
Person._Person.prototype = {
// 正常使用constructor屬性
constructor: Person,
getName: function () {
return this.name;
}
};
// 可以正常使用instanceof操作符
Person.prototype = Person._Person.prototype;
// 標記為已初始化
Person.inited = true;
}
return new Person._Person(name);
}
console.log(new Person('Ralph').getName()); //Ralph
console.log(Person('Ralph').getName()); //Ralph
缺點:
編碼相對較為復雜,需要_Person作為輔助的內部構造函數,且需要手動修改prototype和constructor等屬性
3. 利用instanceof操作符
function Person(name) {
// 如果使用了new,this指向新生成的Person實例
// 如果直接調用Person沒有使用new,這裡的this指向window對象
if (!(this instanceof Person)) {
return new Person(name);
}
this.name = name;
}
Person.prototype.getName = function () {
return this.name;
};
console.log(new Person('Ralph').getName()); //Ralph
console.log(Person('Ralph').getName()); //Ralph
缺點:
在判斷this instanceof Person時需要指明構造函數名稱Person,抽象程度不夠高,修改構造函數名稱時需要手動修改該語句
4. 利用callee屬性和constructor屬性
function Person(name) {
// arguments.callee指向Person函數
// this.constructor僅在使用了new的情形下指向Person函數
if (arguments.callee !== this.constructor) {
return new arguments.callee(name);
}
this.name = name;
}
Person.prototype.getName = function () {
return this.name;
};
console.log(new Person('Ralph').getName()); //Ralph
console.log(Person('Ralph').getName()); //Ralph
缺點:
strict模式下無法使用callee屬性
(全文完)
大話設計模式(帶目錄完整版) PDF+源代碼 http://www.linuxidc.com/Linux/2014-08/105152.htm
JavaScript設計模式 中文清晰掃描版PDF http://www.linuxidc.com/Linux/2015-09/122725.htm