Можно ли динамически обращаться к закрытым переменным в шаблоне модуля?

Есть ли способ получить публичную функцию из шаблона модуля, динамически обращающуюся к закрытым переменным? test1 показывает, что я имею в виду под «динамическим доступом», но с общедоступными переменными

var x = (function(){
    var x=0, y=2, z=5;

    return {
        toast: 123,
        test1: function(arg){
            return this[arg];
        },
        test2: function(){
            // ??
        }
    };
}());

console.log(x.test1("toast")); // 123
console.log(x.test2("y")); // should return 2

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

 privateVarStore[privateVarName]

Но есть ли другое решение для этого?


person Tim Friedrich    schedule 25.12.2011    source источник


Ответы (2)


ДЕМО

Да

Извините, что разочаровал Адама Рэкиса, но вы можете сделать это с помощью (злого) eval:

var x = (function(){
    var x=0, y=2, z=5;

    return {
        toast: 123,
        test1: function(arg){
            return this[arg];
        },
        test2: function(a){
            return eval(a)
        }
    };
}());

console.log(x.test1("toast")); // 123
console.log(x.test2("y")); // should return 2  -> does return 2

Это одно из тех немногих исключений, когда следует использовать eval.

EDIT, согласно предложению Hans B PUFAL (комментарий), вы можете и должны проверить параметр в test2 следующим образом:

test2: function(a){
    return /^[$_a-z][$_a-z0-9]*$/i.test (a) ? eval(a) : undefined;
}
person qwertymk    schedule 25.12.2011
comment
Во избежание проблем с безопасностью рекомендуется добавить проверку того, что параметр test2 действительно является простой переменной: return /^[$_a-z][$_a-z0-9]*$/i.test (a) ? eval(a): не определено; - person HBP; 25.12.2011
comment
@HansBPUFAL: Отличная идея! обязательно добавлю - person qwertymk; 25.12.2011
comment
+1, но могу ли я предложить альтернативную идею проверки: если вы определяете объект, в котором перечислены частные переменные, к которым можно получить доступ через общедоступную функцию, например var accessList = {"x":true,"y":true};, то в function test2(a) вы можете сказать return accessList[a] ? eval(a) : undefined; - преимущество в том, что не только это делает обеспечить безопасность в отношении того, какие строки могут быть переданы в eval, это позволяет вам определять другие действительно частные переменные, к которым нельзя получить доступ через test2(). - person nnnnnn; 25.12.2011
comment
@nnnnnn - мне пришлось прочитать это несколько раз, но это действительно классная идея - person Adam Rackis; 26.12.2011
comment
@qwertymk как насчет того, если метод eval еще не подключен. Я не мог прикрепить это позже. Мне нужен доступ для сканирования веб-страницы и получения доступа к переменной. Инспектор Chrome имеет доступ при отладке и приостановке. Я мог бы связаться с инспектором, сделать что-то подобное, но возможно ли это без? - person mmm; 18.08.2017
comment
@momomo Я не знаю, как это возможно - person qwertymk; 18.08.2017

Нет (по крайней мере, не прибегая к eval, согласно ответу qwertymk).

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

Любой из методов x может получить доступ к y, но не через произнесение this.y, а через прямой доступ к y.

Опять же, y не является свойством вашего объекта x. Это просто локальная переменная в функции, которая создала x, тем самым заставив методы x сформировать над ней замыкание.

Итак, чтобы заставить test2 вернуть y, просто выполните:

test2: function(){
    return y;
}

Чтобы создать метод, позволяющий получить доступ к закрытым переменным, рассмотрите что-то вроде этого:

var x = (function () {
    var privateMembers = { x: 0, y: 2, z: 5 };

    return {
        getPrivate: function (name) {
            return privateMembers[name];
        },
        toast: 123,
        test1: function (arg) {
             return this[arg];
        },
        test2: function () {
           // ??
        }
    };
})();

А потом

alert(x.getPrivate("y")); //alerts 2

Проверьте эту скрипку

person Adam Rackis    schedule 25.12.2011
comment
как бы вы порекомендовали Тиму решить недостающий код в test2()? - person mauris; 25.12.2011
comment
отличный ответ, но это было мое альтернативное решение (создание одного частного объекта для доступа к моим частным переменным в общедоступной функции), мне было интересно, есть ли другой (более красивый) способ сделать это? - person Tim Friedrich; 25.12.2011
comment
@ Тим - не то, что я могу придумать. Лично я считаю вышеописанный способ красивее :) - person Adam Rackis; 25.12.2011
comment
Можно сказать, что test2 является геттером для y. Обычно его можно назвать getY. - person Steve Jorgensen; 25.12.2011
comment
@TimFriedrich - комментарий Стива выше хороший. В зависимости от того, что вы действительно собираетесь делать с test2, подумайте о переименовании. - person Adam Rackis; 25.12.2011
comment
Ping @SteveJorgensen - по вышеуказанному - person Adam Rackis; 25.12.2011