问题
Trying to implement the singleton pattern within CommonJS modules, using Browserify. So far:
// 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
First problem is that I get a maximum call stack exceeded error when I load the built JS file in the browser, but secondly, am I approaching this correctly? Is this possible?
回答1:
First problem is that I get a maximum call stack exceeded error
Well, that comes from your Foo function recursively calling new Foo…
but secondly, am I approaching this correctly?
No. For singletons, you don't need a "class" with a constructor and a prototype - there will only ever be one instance. Simply create one object, most easily with a literal, and return that:
module.exports = {
num: 0,
adder: function(){
this.num++;
}
};
回答2:
The result of any require call is a singleton -- whether a singleton instance or a singleton function or a singleton factory function. Furthermore, a require call should be idempotent -- poorly written CommonJS modules may violate this, so if a CommonJS module has a side effect, that side effect should happen only once no matter how many times that require is called.
The code snippet you have
if(instance){
return instance;
}
// ...
return instance = new Foo();
is a legacy of the kinds of hoops you'd have to jump through if you were using plain old JavaScript to create singletons. It's totally unnecessary when using CommonJS and besides that, it leads to your maximum call stack exceeded issue.
Your code could be rewritten like this:
var Foo = function(){
this.num = 0;
}
Foo.prototype.adder = function(){
this.num++;
};
module.exports = new Foo();
or even more succinctly:
module.exports = {
num: 0,
adder: function(){ this.num++; }
}
because putting the adder method on the prototype doesn't gain you any real efficiency if you're only creating a single instance of Foo, and because you don't need to hide anything in the closure.
来源:https://stackoverflow.com/questions/24283362/singleton-pattern-with-browserify-commonjs