Как работает закрытие JavaScript в этом случае?

#javascript #closures

#javascript #замыкания

Вопрос:

Как работает закрытие JavaScript в этом случае и, если быть более конкретным: что делает (i) в конце?

 for(var i = 0; i < 10; i  ) {
    (function(e) {
        setTimeout(function() {
            console.log(e);  
        }, 1000);
    })(i);
}
  

Также я пытаюсь реализовать это в своем коде, и, похоже, у меня что-то не получается

 for (var i=0; i < len; i  ) {

    var formID = document.forms["form-"   i];
    $(formID).bind("submit", validate);

    $(formID).bind("change", function(i){
        var divI = '#ind-'   i;
        $(divI).css("background-color","green");
    })(i);
}
  

Комментарии:

1.Если вы хотите узнать больше о закрытиях, вот несколько ссылок, которые могут помочь: vimeo.com/1967261 jibbering.com/faq/notes/closures

2. Видео действительно отличное, спасибо

Ответ №1:

Это шаблон, используемый для создания локальной области видимости вокруг переменной. Если бы это не использовалось, то каждый вызов console.log(i) i регистрировал бы значение в (10) после завершения цикла for.

 for(var i = 0; i < 10; i  ) {
    // create new function
    (function(e) {
        // log each counter after 1 second.
        setTimeout(function() {
            console.log(e);  
        }, 1000);
    // execute it with the counter
    })(i); 
}
  

Вышесказанное аналогично этому.

 function foobar(e) {
    setTimeout(function() {
         console.log(e);
    }, 1000);
}

for (var i = 0; i < 10; i  ) {
    (
        foobar
    )(i);
}
  

Настоящая проблема здесь заключается в создании функций в цикле. не делайте этого 🙂

Ваш код

 for (var i=0; i < len; i  ) {

    var formID = document.forms["form-"   i];
    $(formID).bind("submit", validate);
    // create a full closure around the block of code
    (function() {
        $(formID).bind("change", function(i){
            var divI = '#ind-'   i;
            $(divI).css("background-color","green");
        })//(i); Don't call (i) here because your just trying to execute the 
        // jQuery element as a function. You can't do this, you need to wrap 
        // an entire function around it.
    })(i);
}
  

Но это неправильно, вы хотите делегировать эту работу чему-то другому.

 function makeGreen(form, i) {
    $(form).change(function() {
         $("#ind-" i).css("background-color", "green");
    });
}

for (var i=0; i < len; i  ) {
    var formID = document.forms["form-"   i];
    $(formID).bind("submit", validate);
    // call a helper function which binds the change handler to the correct i
    makeGreen(formID, i);
}
  

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

 function makeGreen() {
     var divId = $(this).data("div-id");
     $(divId).css("background-color", "green");
}

for (var i=0; i < len; i  ) {
    $(document.forms["form-"   i])
        .bind("submit", validate)
        // store i on the form element
        .data("div-id", "#ind-"   i)
        // use a single event handler that gets the divId out of the form.
        .change(makeGreen);
}
  

Редактировать

 ( // contain the function we create.
    function(parameterA) {
         window.alert(parameterA);
    }
) // this now points to a function
("alertMessage"); // call it as a function.
  

Это то же самое, что

 ( // contain the window.alert function
    window.alert
) // it now points to a function
("alertMessage"); // call it as a function
  

Комментарии:

1. спасибо @ Raynos, я вижу это, но я не совсем понимаю, как это работает и как это реализовать в моем коде (я отредактировал вопрос), есть предложения? 🙂

2. 1 за «Реальная проблема здесь заключается в создании функций в цикле. не делайте этого » (предполагая, что вы говорите о немедленно вызванном ). Возможно, добавить пример именованной функции?

3. Лично я не уверен, что мне не нравятся подобные встроенные лямбды. Я думаю, это вопрос стиля, и, конечно же, на это влияет опыт работы с другими функциональными языками. Я вижу обе стороны аргумента, но я не уверен, какая из них выигрывает 🙂

4. @Pointy @T.J.Crowder Я думаю, что второй пример лучше, вместо привязки этих данных к закрытию вы привязываете их к элементу DOM, который является гораздо «более дешевым» местом для его существования. @T.J.Crowder Также извините, что испортил ваш ответ

5. @Raynos: Я согласен. И, ЛОЛ, не беспокойтесь, отличный ответ.

Ответ №2:

Хотя это и не прямой ответ на вопрос о закрытии, вот мой взгляд на проблему.

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

Тот факт, что в именовании форм присутствует шаблон, действительно упрощает задачу

 $('form[id^="form-"]').submit(validate)
     .change(function(){
          var divI = '#ind-'   this.id.replace('form-','');
          $(divI).css("background-color","green");
     });
  

демо http://jsfiddle.net/gaby/q8WxV /

Комментарии:

1. спасибо, но я не понимаю form[id^="form-"] , что это делает?

2. @IlyaD, это селектор атрибута, который начинается с . Это означает найти все, forms чьи id начинаются с "form-" .