Как я могу перевести свой JavaScript Module-Singleton на поддерживающие экземпляры?

Я писал приложение и добился большого успеха, разбивая различные части функциональности на так называемый шаблон «Модуль», где у вас есть самоисполняющийся синглтон с открытыми и закрытыми членами.

var WidgetModule = (function($, options) {

    // Private variable
    var someVar;

    // Private functions
    function somePrivateFunction() {

    }

    // Define the public members
    var self = {
        init: function() {

        },
        someFunction: function() {

        }
    };

    return self;

})(jQuery, options);

Теперь я столкнулся со случаем, когда у меня есть несколько модулей, из которых я хотел бы создать несколько экземпляров.

Я знаю, что этот шаблон основан на синглтоне, но мне интересно, есть ли безболезненный способ изменить этот шаблон для поддержки создания их экземпляров?


person Mithrax    schedule 16.05.2011    source источник


Ответы (2)


Когда мне нужна общая функциональность для нескольких объектов, вот шаблон, который я обычно использую (с поправкой на представленный вами код):

var Widget = (function($) {
    var pubs = Widget.prototype;

    // Private variable -- global to all instances
    var someVar;

    // The constructor    
    function Widget(options) {
        var privateInstanceVar;

        this.privateInstanceFunc = function() {
            return privateInstanceVar;
        };
    }

    // Private functions -- global to all instances
    function somePrivateFunction() {

    }

    // Define the public members
    pubs.init = function() {

    };

    pubs.someFunction = function() {

    };

    return Widget;

})(jQuery);

Использование:

var w = new Widget({someOption: "here"});

Как видите, вы можете совместно использовать личные данные между всеми экземплярами, созданными конструктором, и, если вы действительно хотите, вы можете иметь личные данные, которые используются совместно только с определенными выбранными функциями экземпляра. Эти функции должны быть созданы в конструкторе, что имеет последствия для повторного использования, в то время как функции, которым не нужны действительно частные данные экземпляра, могут быть в прототипе и, следовательно, совместно использоваться всеми экземплярами.

А еще лучше, поскольку у вас уже есть удобная функция обзора, вы можете помочь своим инструментам помочь вам дав своим общедоступным функциям настоящие имена:

    pubs.init = Widget_init;
    function Widget_init() {

    }

В основном я не кодирую описанное выше, потому что я определил вспомогательную фабрику, которая делает его немного более кратким (и упрощает специализацию функциональности, например, Car наследует функциональность от Vehicle); подробности здесь.

person T.J. Crowder    schedule 16.05.2011
comment
@TJ Мой пример слишком упрощен, чего-то не хватает? Тх - person Mic; 17.05.2011
comment
@Mic: я опубликую комментарий к вашему ответу. - person T.J. Crowder; 17.05.2011
comment
Зачем передавать jQuery как $? Разве он уже не доступен через $? Я немного новичок в JS, поэтому я предполагаю, что я чего-то не понимаю. - person AaronLS; 06.11.2012
comment
@AaronLS: Зачем передавать jQuery как $? Разве он уже не доступен через $? Не обязательно, jQuery имеет режим без конфликтов где $ не используется для jQuery. Поскольку плагин по своей природе используется в средах, над которыми автор не имеет контроля, нужно разрешить это... - person T.J. Crowder; 06.11.2012

Что насчет этого:

function WidgetModule(options){
    //var $ = jQuery;
    // Private variable
    var someVar;

    // Private functions
    function somePrivateFunction() {

    }

    // Define the public members
    var self = {
        init: function() {
          console.log(options.id);
        },
        someFunction: function() {

        }
    };

    return self;
}

var w1 = WidgetModule({id:1}),
    w2 = WidgetModule({id:2});

w1.init(); // --> 1
w2.init(); // --> 2
person Mic    schedule 16.05.2011
comment
В комментарии к моему ответу вы спросили, не пропало ли что-то в вашем. По сути, это работает и должно иметь вывод, который вы показываете. Однако у него нет WidgetModule-широкой области (только область действия на уровне экземпляра), поэтому нет возможности обмениваться данными или функциями между экземплярами (то, что вы бы назвали методами/данными уровня класса в системе на основе классов) . Каждый экземпляр будет иметь собственную копию всего (включая реализации функций). Это нормально для модулей и т.п., но для объектов, которых у вас будет много, вы захотите поделиться ими, где сможете. (продолжение) - person T.J. Crowder; 17.05.2011
comment
(продолжение) В JavaScript есть целый прототип механизма для этого (повторного использования). Вышеприведенное также немного необычно; предполагается вызывать фабрику через new (например, var w1 = new WidgetModule({id:1});). Это будет работать, если вы вызовете его через new, но отбросит объект, созданный new, в пользу того, который вы вернете; небольшой отток памяти (вероятно, в значительной степени безвредный). Вышеприведенное также нарушает instanceof (w1 instanceof WidgetModule будет ложным). И одна из моих любимых мозолей, init и someFunction анонимны. Но это работает, и я уже видел подобные модели. Лучший, - person T.J. Crowder; 17.05.2011