(Показывая) Шаблон модуля, общедоступные переменные и оператор возврата

Я пытаюсь понять, как работают public` свойства в (Revealing) Module Pattern. Преимущество, на которое указал Карл Дэнли "Шаблон раскрывающегося модуля"< /а> это:

Явно определенные общедоступные методы и переменные, которые повышают читабельность.

Давайте посмотрим на этот код (fiddle):

var a = function() {
    var _private = null;
    var _public = null;
    function init() {
        _private = 'private';
        _public = 'public';
    }
    function getPrivate() {
        return _private;
    }
    return {
        _public : _public,
        init : init,
        getPrivate : getPrivate,
    }
}();

a.init();
console.log( a._public ); // null
console.log( a.getPrivate() ); // "private"

Он возвращает null при вызове a._public. Теперь я могу манипулировать этим общедоступным свойством, например a._public = 'public';. Но я не могу изменить его из своего объекта. Или, по крайней мере, эти изменения не проходят. Я как бы ожидал, что это будет "public", так как он был обновлен методом init раньше.

Означает ли это, что у меня не может быть методов, обрабатывающих public свойства? Тогда свойства public в этом шаблоне не имеют большого смысла, верно? Я также безуспешно пробовал это (fiddle):

return {
    _pubic : _public,
    init2 : function() {
        _public = 'public';
    }
}

И последнее, но не менее важное: у меня есть вопрос относительно всего заявления return. Почему нельзя просто использовать return this;, чтобы сделать все общедоступным? Поскольку this должен быть контекстом самовызываемой функции, не должна ли она просто возвращать в ней все? Почему я должен создавать еще один объект, который возвращается? В этой скрипте он возвращает объект window.


person lampshade    schedule 30.05.2015    source источник


Ответы (3)


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

Нет, это означает, что у вас не может быть общедоступных переменных. var _public — это переменная, и она недоступна извне, и когда вы изменяете приватную переменную, это не будет отражаться в вашем общедоступном свойстве ._public.

Если вы хотите сделать что-то общедоступным, используйте свойства:

var a = function() {
    var _private = null;
    function init() {
        _private = 'private';
        this._public = 'public';
    }
    function getPrivate() {
        return _private;
    }
    return {
        _public : null,
        init : init,
        getPrivate : getPrivate,
    }
}();

Я могу манипулировать этим общедоступным свойством, например a._public = 'public';. Но я не могу изменить его из своего объекта.

Вы можете использовать this в методах вашего объекта, как показано выше. Или вы используете a для ссылки на объект или, возможно, даже сохраняете локальную ссылку на объект, который вы возвращаете. См. здесь различия.

Или, по крайней мере, эти изменения не проходят

Да, потому что переменные отличаются от свойств (в отличие от некоторых других языков, таких как Java, и с исключениями для глобальных). Когда вы экспортируете public: _public в свой литерал объекта, он берет только текущее значение из переменной _public и создает с ним свойство объекта. Постоянной ссылки на переменную нет, и изменения в одной не отражаются в другой.

Почему нельзя просто использовать return this;, чтобы сделать все общедоступным? Поскольку это должен быть контекст самовызываемой функции, разве она не должна просто возвращать в ней все?

Переменные являются частью области в JavaScript. (За исключением глобальной) эти области не являются объектами, доступными для языка.

this ключевое слово не относится к этой области. функции, а в контексте, предоставленном вызовом. Это может быть базовая ссылка в вызове метода, новый экземпляр в вызове конструктора или просто ничего в базовом вызове функции, подобном вашему (или глобальный объект window в свободном режиме).

person Bergi    schedule 30.05.2015
comment
Большое спасибо за очень краткое и полезное объяснение. - person lampshade; 30.05.2015
comment
@T.J.Crowder: Спасибо за доверие :-) На самом деле я пошел на обед сразу после публикации этой заметки, увидев, что вы уже ответили… К сожалению, вы удалили свой ответ, и его содержание даже не сохраняется в истории :-/ - person Bergi; 30.05.2015
comment
Да, я тоже видел его ответ, и в нем тоже было несколько хороших идей. Но вдруг оно исчезло. - person lampshade; 30.05.2015

В определении вашего модуля _public копируется по значению, поскольку в javascript только объекты назначаются по ссылке. После этого он вообще не имеет ссылки на локальную переменную _public. Поэтому это будет работать только в том случае, если вы либо «упаковываете» _public в объект, поэтому он копируется по ссылке, либо вы также ссылаетесь на свойство объекта в своем модуле, имея только одну ссылку на локальную переменную:

var a = function() {
    var module = {
        _public: null
    };

    // use module._public here 

    return module;
}();

a._public = "foo";
person Gerard van Helden    schedule 30.05.2015
comment
Похоже на классный трюк упаковывать вещи в объекты. Спасибо. - person lampshade; 30.05.2015

Вы можете использовать эту конструкцию для создания нового класса

function a(){
    var _private = null;
    this.public = null;
    this.getPrivate = function(){
        return _private;
    };

    function init(){
        _private  = "private";
        this.public = "public";
    }

    init.apply(this, arguments);
}

//static function
a.create = function(){
    return new a();
};

//using
var b = new a();
//or
var b = a.create();
person Microshine    schedule 30.05.2015