JS: наследование переменных в анонимных функциях - область видимости - PullRequest
4 голосов
/ 11 мая 2010

Эй, ребята, кто-то из doctype прислал меня сюда.
Короче говоря:

var o="before";
x = function() //this needs to be an anonymous function
{
  alert(o); //the variable "o" is from the parent scope
};
o="after"; //this chages "o" in the anonymous function

x();
//this results in in alert("after");
//which is not the way i want/need it

на самом деле мой код несколько сложнее.
Мой скрипт перебирает множество html-объектов и добавляет прослушиватель событий для каждого элемента.
я делаю это, объявляя анонимную функцию для каждого элемента и вызываю другую функцию с идентификатором в качестве аргумента. этот идентификатор представлен переменной «o» в этом примере.

Подумав, я понимаю, почему это так,
но есть ли способ заставить js оценить o, когда я объявляю анонимную функцию, не имея дело с атрибутом id и не получая оттуда свой ID?

мой полный исходный код здесь: http://pastebin.com/GMieerdw анонимная функция в строке 303

Ответы [ 3 ]

8 голосов
/ 11 мая 2010

Вам необходимо создать замыкание вашей переменной o. Вы можете сделать это, назначив функцию, которая принимает значение, возвращает функцию, которая использует это значение. Ваш пример можно изменить так, чтобы получить желаемый эффект:

var o="before";
x = function(inner) {
    return function()
    {
      alert(inner);
    }
} (o); //here, the anonymous function is called, which will return another function which uses o
o="after";

x();//prints "before"

Более подробное описание см. В статье MDC , в которой есть раздел об использовании замыканий с циклами.

Эта же техника может быть применена в вашем цикле. Примерно так вы и хотели бы сделать:

var fn = function(x, y) {
    return function() {
        rr_download_start(x, y);
    }
} (i, this);
link.addEventListener('click', fn ,false);
6 голосов
/ 11 мая 2010

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

var o = 0;
for(var i=0;i<elements.length;i++){
    (function(obj,variable){
        obj.onclick = function(){
            alert(variable);
        }
    })(elements[i],o);
    o++;
}

Это должно предупредить «o» при любом значении, которое было во время цикла, вместо предупреждения о конечном значении «o».

Надеюсь, это поможет.

0 голосов
/ 11 мая 2010

Один из способов - создать функцию curry :

function curry(fun, arg) {
  return function() {
    return fun(arg);
  };
};

// start loop 
var o="before";
x = curry(function(o) {
  alert(o);
}, o);
o="after";

x(); // "before"

Другим способом является использование внешнего источника данных - поскольку this будет зависеть от того, где была вызвана функция, вы можете сохранить значение в узле DOM, к которому привязан обработчик. Таким образом, вы можете использовать одну функцию вместо множества анонимных функций. У этого метода есть несколько предостережений (циклические ссылки могут вызвать утечку памяти в IE6), но фреймворки могут иметь хорошую чистую оболочку для него. Например в jQuery вы можете написать:

function doStuff() {
  alert($(this).data('o'));
}

// start loop
var o="before";
someDomElement.data('o', 'before');
someDomElement.bind('someEvent', doStuff);
o="after";

someDomElement.trigger('someEvent'); // "before"
...