Подтвердить что ты не робот

Шаблон Singleton с Browserify/CommonJS

Попытка реализовать шаблон singleton в модулях CommonJS, используя Browserify. До сих пор:

//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

Первая проблема заключается в том, что я получаю ошибку maximum call stack exceeded при загрузке встроенного JS файла в браузере, но, во-вторых, я правильно подошел? Возможно ли это?

4b9b3361

Ответ 1

Первая проблема заключается в том, что я получаю максимальный стек вызовов превышен error

Ну, это происходит из вашей функции Foo, которая рекурсивно вызывает new Foo...

но во-вторых, правильно ли я подошел?

Нет. Для синглетов вам не нужен "класс" с конструктором и прототипом - будет только один экземпляр. Просто создайте один объект, наиболее легко с литералом, и верните его:

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

Ответ 2

Результатом любого вызова require является singleton - будь то одиночный экземпляр или одноэлементная функция или одиночная функция factory. Кроме того, требуемый вызов должен быть идемпотентным - плохо написанные модули 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++; }
}

потому что использование метода adder на прототипе не дает вам реальной эффективности, если вы создаете только один экземпляр Foo и потому, что вам не нужно ничего скрывать в закрытии.