Подтвердить что ты не робот

Доступ к переменным, захваченным закрытием

Мне было интересно, есть ли способ доступа к переменным, захваченным замыканием в функции извне функции; например если у меня есть:


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);
4b9b3361

Ответ 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();
    }
}