Присоединение события функции onchange к переменной - PullRequest
6 голосов
/ 21 апреля 2011

Я недавно попал в замыкания и анонимные функции, и мне интересно, является ли мой код правильным способом (это работает!):

newInput.onchange = function(x){
     return function(){
          PassFileName(x);  
     }
}(counter);

, так что это в цикле, который "сохраняет "текущее значение" счетчика "(1,2,3 ...).Если у меня не было функции возврата, тогда 'counter' всегда будет последним значением 'counter'.

Правильно ли я подхожу к этому с этим кодом?или есть лучший способ "захватить" текущий счетчик и прикрепить его к событию onchange?

спасибо!

Ответы [ 2 ]

5 голосов
/ 21 апреля 2011

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

    newInput.onchange = (function(x){
//                      ^--- here
         return function(){
              PassFileName(x);  
         }
    })(counter);
//   ^--- and here

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


Обновление :

Хотя ваш подход хорош, стоит отметить, что он немного расточителен.;-) Он создает две функции на каждой итерации вашего цикла, внешнюю анонимную и внутреннюю анонимную.Обе эти функции остаются неизменными (за исключением оптимизации реализации, которая, как вы знаете, не будет у некоторых двигателей).Вместо этого у вас может быть только одна на цикл плюс одна фабричная функция:

// In the loop
newInput.onchange = makeHandler(x);

// Outside the loop
function makeHandler(x){
     return function(){
          PassFileName(x);  
     };
}

Некоторые могут посчитать, что читать легче (я, конечно, так), при условии, что makeHandler все еще достаточно близко к циклу, что выне теряйте трек.

Использование заводской функции также дает вам возможность не закрывать область действия else , хотя тогда вам придется отодвинуть заводскую функцию дальше (например,в ограниченном объеме).

Вы можете также рассмотреть универсальную функцию curry , например , предоставленную Prototype .Общий curry, который не не передает аргументы времени вызова, выглядит следующим образом:

function curry(f) {
    var args = arguments;
    return function() {
        f.apply(undefined, args);
    };
}

Но обычно более полезно (но дороже) иметь такой, который передает также аргументы времени выполнения.Вот дешевый и грязный (не оптимизированный; с оптимизацией накладные расходы на время вызовов могут быть заметно сокращены):

function curry(f) {
    var args = Array.prototype.slice.call(arguments, 1);
    return function() {
        f.apply(undefined,
                args.concat(Array.prototype.slice.call(arguments)));
    };
}

Преимущество в обоих случаях заключается в том, что вы не закрываете ничего нового, что можетеизбегать.


Не по теме : Кроме того, технически , вы полагаетесь на ужас, который заключается в вставке точки с запятой (должна быть точка с запятой вконец вашего return заявления), на которое я всегда выступаю, не полагаясь.Впрочем, чертовски безопасно в этом примере.; -)

3 голосов
/ 21 апреля 2011

То, что вы делаете, довольно стандартно, и в этом нет ничего плохого.Тем не менее, есть похожий метод, который я предпочитаю:

(function (x) {
    newInput.onchange = function () {
        PassFileName(x);
    };
})(counter);

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

...