尝试使用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
错误,但其次,我是否正确接近了这个问题?这可能吗?
答案 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
方法放在原型上并不能获得任何实际效率关闭中的任何事情。