手机版
你好,游客 登录 注册
背景:
阅读新闻

JavaScript中实现不加new关键字的构造函数

[日期:2015-10-11] 来源:Linux社区  作者:front-end-ralph [字体: ]

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

本文永久更新链接地址http://www.linuxidc.com/Linux/2015-10/124027.htm

linux
本文评论   查看全部评论 (0)
表情: 表情 姓名: 字数

       

评论声明
  • 尊重网上道德,遵守中华人民共和国的各项有关法律法规
  • 承担一切因您的行为而直接或间接导致的民事或刑事法律责任
  • 本站管理人员有权保留或删除其管辖留言中的任意内容
  • 本站有权在网站内转载或引用您的评论
  • 参与本评论即表明您已经阅读并接受上述条款