Когда я возвращаю объект из функции конструктора JavaScript (избегая 'new'), как мне реализовать открытые члены? - PullRequest
2 голосов
/ 15 июля 2010

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

например, ниже приведен идентификатор элемента с помощью myobj.getId (), но myobj.id не определен.

function setup(){
    var myobj = MyObject();
    myobj.initialize();
    alert(myobj.getId()); // returns 3, as expected
    alert(myobj.id); // returns undefined
}
function MyObject(){
    var id;
    function initialize(){
        //do some stuff that initializes data including...
        id = 3;
    }
    return{
        initialize:initialize,
        id:id,
        getId:function(){ return id;}
    }
}

Нет ли способа заставить myobj.id работать, возвращая значение, которое было установлено в initialize ()?

Ответы [ 3 ]

3 голосов
/ 15 июля 2010

Ваша проблема в том, что вы не пользуетесь закрытием. Строка id:id создает новую переменную в качестве члена возвращаемого литерала объекта. Это имеет значение по умолчанию undefined. Затем вы присваиваете себе ту же самую переменную id, снова undefined.

Кроме того, модуль - это отдельный экземпляр объекта, а не фабричная функция. Попробуйте что-то вроде этого:

var myModule = (function(opts) {
    var foo = opts.foo || 0,    //private variables with default values
        bar = opts.bar || 0,    // if none are passed in

        product = function() {      //private method
            return (foo * bar);
        };

    return {
        getFoo : function() {   //public methods
            return foo;
        },
        fooTimesBar : function() {
            return product();
        }
    }
})({
    foo : 5,                    //options object
    bar : 7
});

Ядром шаблона модуля является самовыполняющаяся анонимная функция, которая объявляет переменные и затем возвращает объект, имеющий привилегированный доступ к этим переменным через замыкание .

Дополнительные символы в конце, в данном случае содержащие литерал объекта с некоторыми передаваемыми опциями, выполняют функцию, которая затем возвращает объект и присваивает его myModule.

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

Все это приводит к одному экземпляру объекта в myObject. Можно создать не более одного, что является определением модуля. Аналогичный подход может быть использован для создания фабричной функции.

1 голос
/ 15 июля 2010

Причина в том, что ваша переменная id по умолчанию установлена ​​в undefined, и ее тип также будет undefined. Теперь, поскольку неопределенный тип является примитивным, ваше назначение в возвращаемом объекте будет назначением значения, а не ссылкой. Таким образом, obj.id станет undefined в экземпляре и будет отличаться от переменной id в функции конструктора.

Теперь initialize изменит id в функции конструктора, а getId вернет тот же id, но obj.id будет ссылаться на свойство объекта undefined.

function MyObject(){
    // initialize is used as a public function so
    // this will always refer to the current instance
    function initialize(){
        this.id = 3;
    }
    return {
        // no need to define id here it will 
        // report undefined on access by default
        initialize: initialize,
        getId:function(){ return this.id; }
    }
}

Запустите весь материал, чтобы убедиться, что он работает как положено.

0 голосов
/ 25 мая 2012

Вы можете решить эту проблему и по-прежнему поддерживать синтаксический сахар шаблона модуля Revealing, возвращая кешированный объект вместо анонимного.

например:

NAMESPACE.Module = (function () {

    //All public members go on api
    var api = {}
    api.id = 3;

    //Private members
    var self,
        foo,
        bar;


    /**
        @public
    */
    api.init = function () {
        self = this;
        console.log(this); //NAMESPACE.Module
    }


    /**
        @private
    */
    function _privateFunction() {
        console.log(self); //NAMESPACE.Module
    }

    return api;
}());
...