使用Browserify / CommonJS的单例模式

时间:2014-06-18 10:35:54

标签: javascript browserify commonjs

尝试使用Browserify在CommonJS模块中实现单例模式。到目前为止:

// foo.js

var instance = null;

var Foo = function(){
    if(instance){
        return instance;
    }
    this.num = 0;
    return instance = new Foo();
}

Foo.prototype.adder = function(){
    this.num++;
};

module.exports = Foo();

// main.js

var foo = require('./foo.js');
console.log(foo.num); // should be 0
foo.adder(); // should be 1
var bar = require('./foo.js');
console.log(bar.num); // like to think it'd be 1, not 0

第一个问题是当我在浏览器中加载构建的JS文件时出现maximum call stack exceeded错误,但其次,我是否正确接近了这个问题?这可能吗?

2 个答案:

答案 0 :(得分:28)

  

第一个问题是我得到一个超出最大调用堆栈的错误

嗯,这来自你的Foo函数递归调用new Foo ...

  

但其次,我正确接近这个吗?

没有。对于单身人士,你不需要一个"班级"使用构造函数和原型 - 只会有一个实例。只需创建一个对象,最容易用文字创建,然后返回:

module.exports = {
    num: 0,
    adder: function(){
        this.num++;
    }
};

答案 1 :(得分:22)

任何require调用的结果都是单例 - 无论是单例实例还是单例函数还是单例工厂函数。此外,require调用应该是幂等的 - 写得不好的CommonJS模块可能会违反这一点,所以如果CommonJS模块有副作用,那么无论调用多少次都会发生这种副作用。

您拥有的代码段

if(instance){
    return instance;
}
// ...
return instance = new Foo();
如果您使用普通的旧JavaScript来创建单例,那么

是您必须跳过的各种箍的遗产。使用CommonJS时完全没有必要,除此之外,还会导致maximum call stack exceeded问题。

您的代码可以像这样重写:

var Foo = function(){
   this.num = 0;
}

Foo.prototype.adder = function(){
   this.num++;
};

module.exports = new Foo();

甚至更简洁:

module.exports = {
   num: 0,
   adder: function(){ this.num++; }
}

因为如果您只创建一个Foo的单个实例,并且因为您不需要隐藏,那么将adder方法放在原型上并不能获得任何实际效率关闭中的任何事情。