Доступ к переменным, захваченным закрытием
Мне было интересно, есть ли способ доступа к переменным, захваченным замыканием в функции извне функции; например если у меня есть:
A = function(b) {
var c = function() {//some code using b};
foo: function() {
//do things with c;
}
}
есть ли способ получить доступ к c
в экземпляре A
. Что-то вроде:
var a_inst = new A(123);
var my_c = somejavascriptmagic(a_inst);
Ответы
Ответ 1
Переменные в закрытии не могут быть напрямую доступны снаружи любыми способами. Тем не менее, замыкания в этом закрытии, которые имеют переменную в области видимости, могут получить к ним доступ, и если вы сделаете эти закрытия доступными извне, это почти так же хорошо.
Вот пример:
var A = function(b) {
var c = b + 100;
this.access_c = function(value) {
// Function sets c if value is provided, but only returns c if no value
// is provided
if(arguments.length > 0)
c = value;
return c;
};
this.twain = function() {
return 2 * c;
};
};
var a_inst = new A(123);
var my_c = a_inst.access_c();
// my_c now contains 223
var my_2c = a_inst.twain();
// my_2c contains 446
a_inst.access_c(5);
// c in closure is now equal to 5
var newer_2c = a_inst.twain();
// newer_2c contains 10
Надеюсь, это немного полезно для вас...
Ответ 2
Простой eval внутри области закрытия может все же получить доступ ко всем переменным:
function Auth(username)
{
var password = "trustno1";
this.getUsername = function() { return username }
this.eval = function(name) { return eval(name) }
}
auth = new Auth("Mulder")
auth.eval("username") // will print "Mulder"
auth.eval("password") // will print "trustno1"
Но вы не можете напрямую перезаписать метод, который обращается к закрывающей области (например, getUsername()), вам нужен простой eval-трюк:
auth.eval("this.getUsername = " + function() {
return "Hacked " + username;
}.toSource());
auth.getUsername(); // will print "Hacked Mulder"
Ответ 3
Ответы выше правильные, но они также подразумевают, что вам нужно будет изменить функцию, чтобы увидеть эти закрытые переменные.
Переопределение функции с помощью методов getter выполнит задачу.
Вы можете сделать это динамически.
См. Пример ниже
function alertMe() {
var message = "Hello world";
console.log(message);
}
//adding the getter for 'message'
var newFun = newFun.substring(0, newFun.lastIndexOf("}")) + ";" + "this.getMessage = function () {return message;};" + "}";
//redefining alertMe
eval(newFun);
var b = new alertMe();
теперь вы можете получить доступ к сообщению, вызвав b.getMesage()
Конечно, вам придется иметь дело с несколькими вызовами alertMe, но это просто простой фрагмент кода, доказывающий, что вы можете это сделать.
Ответ 4
Нет, не без функции getter на A
, которая возвращает c
Ответ 5
Весь смысл этого шаблона состоит в том, чтобы предотвратить доступ к "c" извне. Но вы можете получить доступ к foo() как к методу, поэтому убедитесь, что он увидит 'c' в своей области:
A = function(b) {
var c = function() {//some code using b};
this.foo = function() {
return c();
}
}