歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux編程 >> Linux編程

JavaScript中實現不加new關鍵字的構造函數

一般而言,在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

Copyright © Linux教程網 All Rights Reserved