Как я могу вызвать общедоступный метод из закрытого при использовании шаблона модуля javascript?

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

Обратите внимание, что я пытаюсь применить шаблон модуля. Пример рабочего кода можно найти на странице jsfiddle.net.

// how can i access a public method from a private one?
// (in this example publicAlert from privateMethod)
// this refers to the window object.

$(function() {
var modulePattern = (function($)
{
    var privateMethod = function()
    {
        appendText("called privateMethod()");
        this.publicAlert();
    };

    var appendText = function(texToAppend)
    {
        var text = $('#output').text() + " | " + texToAppend;
        $('#output').text(text);
    };

    return {
        publicMethod : function()
        {
            appendText("called publicMethod()");
            privateMethod();
        },

        publicAlert : function()
        {
            alert("publicAlert");
        }
    };
});

mp = new modulePattern($);
mp.publicMethod();
});

person Ota    schedule 21.12.2010    source источник
comment
Да, вы неправильно используете шаблон модуля. Вы должны немедленно выполнять анонимную функцию, а не использовать «новый». И вам также никогда не нужно использовать ключевое слово «это». Вам также не нужно оборачивать модуль в готовый обработчик jquery, только вызовы к нему. См. это: jsfiddle.net/sVxvz   -  person david    schedule 22.12.2010
comment
Хороший ответ уже есть: stackoverflow.com/questions/1111725/   -  person user11153    schedule 30.10.2013


Ответы (2)


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

$(function() {
    var modulePattern = (function($) {
        var privateMethod = function() {
            appendText("called privateMethod()");
            publicAlert();
        };

        var appendText = function(text) {
            var text2 = $('#output').text() + " | " + text;
            $('#output').text(text2);
        };

        var publicAlert = function(){
            alert("publicAlert");            
        };

        return {
            publicMethod: function() {
                appendText("called publicMethod()");
                privateMethod();
            },

            publicAlert: publicAlert
        };
    });

    mp = new modulePattern($);
    mp.publicMethod();
});

[Изменить] Я бы также посоветовал вам выработать привычку нажимать кнопку «jslint» в верхней части jsfiddle, в вашем коде отсутствовало несколько точек с запятой, и вы также повторно объявили переменную «text» внутри вашей функции appendText (она уже прошел)

Кроме того, вы используете шаблон модуля немного иначе, чем я его изучил. У вас есть ссылка на ваш справочный материал?

Вот как я бы сделал шаблон модуля, каким я его знаю: http://jsfiddle.net/sVxvz/[/Править]

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

var testModule = (function($) {
    var privateMethod = function() {
        appendText("called privateMethod()");
        testModule.publicAlert();
    };

    var appendText = function(text) {
        var text2 = $('#output').text() + " | " + text;
        $('#output').text(text2);
    };

    return {
        publicMethod: function() {
            appendText("called publicMethod()");
            privateMethod();
        },
        publicAlert: function() {
            alert("publicAlert");
        }
    };
}(jQuery));

$(function() {
    testModule.publicMethod();
});

Но мне это не очень нравится, потому что общедоступные методы могут быть перезаписаны. кто-то может пойти testModule.publicAlert = function(){EVIL CODE OF DOOM;};, и ваша внутренняя работа с радостью выполнит его.

person david    schedule 22.12.2010
comment
Спасибо за ваш отзыв. И извините за нечистый код, я совершенно забыл кнопку jslint, потому что думал о своей проблеме :) Вот два источника, которые я использую в качестве ссылки для шаблона: yuiblog и ajaxian - person Ota; 22.12.2010
comment
Я думаю, что ваше решение будет самым простым, но помимо переназначения метода publicAlert с частного на общедоступный, нет ли способа ввести правильную область для этого? - person Ota; 22.12.2010
comment
принимая предложение @david и доводя его до того, что вам не нужно дважды определять общедоступные методы/свойства jsfiddle.net /subhaze/JJwrU/3 - person subhaze; 22.12.2010
comment
Да, в обеих этих ссылках они автоматически выполняют функцию, которую вы не делаете. Вы проверили ссылку, которую я добавил внизу? jsfiddle.net/sVxvz Кроме того, я не дважды определяю общедоступные методы, они определяются один раз, а затем выставляется через возвращаемый объект. Это похоже на то, что вы сделали, за исключением того, что вы создаете возвращаемый объект перед его возвратом, что позволяет внутренним функциям видеть его. Довольно умно! - person david; 22.12.2010
comment
И относительно: «введение правильной области для этого» - то, что вы спрашиваете, на самом деле не имеет смысла. Шаблон модуля никогда не должен включать ключевое слово this. - person david; 22.12.2010
comment
@david, где в шаблоне сказано, что вы должны выполнить его автоматически? Я думал, что это открыто для разработчика. В основном вы создаете синглтон, когда автоматически выполняете его. Нельзя ли присвоить это переменной с таким именем в методе инициализации и использовать ее для получения правильной области видимости? Но это решение звучит намного сложнее, чем два опубликованных. Я не могу решить, какой метод предпочесть, тот, который выложили вы, или subhaze. :) - person Ota; 22.12.2010
comment
Потому что автовыполнение — это огромная часть шаблона. Вы не создаете новый объект, вы создаете область действия анонимной функции, немедленно выполняете ее, чтобы создать замыкание вокруг внутренних «частных» переменных, а затем возвращаете специально созданный объект, чтобы разрешить ограниченный доступ к функциям, которые попали в ловушку. внутри замыкания. - person david; 22.12.2010
comment
Если вы хотите иметь несколько «копий» модуля, вы можете выполнять функцию несколько раз, каждый раз создавая новое замыкание. Но вы никогда не используете ключевое слово «новое». Я бы сделал это так: jsfiddle.net/qGtJX - person david; 22.12.2010

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

this.methodName = function(){...}

переменная $this назначается текущему экземпляру (this), поэтому вы можете использовать ее из частных (или общедоступных) методов для доступа к любым методам или атрибутам этого экземпляра.

Вилка:

http://jsfiddle.net/FNjJq/

person driangle    schedule 22.12.2010
comment
То, что вы делаете, просто создаете новый объект. Это вообще не шаблон модуля. - person david; 22.12.2010
comment
Afaik, вы просто создаете новый объект внутри объекта modulePattern. В результате вы больше не применяете шаблон - person Ota; 22.12.2010