Я не понимаю пример закрытия для ошибки цикла из mdn

#javascript #loops #closures

Вопрос:

1.Пример MDN

Приведенный ниже фрагмент кода назначает функцию, отображающую текст справки для каждого текстового поля при фокусировке, вот ссылка на JsFiddle: https://jsfiddle.net/v7gjv/8164/

 function showHelp(help) {
          document.getElementById('help').textContent = help;
        }
        
        function setupHelp() {
          var helpText = [
              {'id': 'email', 'help': 'Your e-mail address'},
              {'id': 'name', 'help': 'Your full name'},
              {'id': 'age', 'help': 'Your age (you must be over 16)'}
            ];
        
          for (var i = 0; i < helpText.length; i  ) {
            var item = helpText[i];
            document.getElementById(item.id).onfocus = function() {
              showHelp(item.help);
            }
          }
        }
        
        setupHelp();
 

Но он будет отображать только последний текст справки, независимо от того, какой из трех входных данных сфокусирован. MDN говорит, что функция, назначенная всем трем входам, является закрытием, поэтому они используют одну и ту же ссылку на переменную HelpText, когда цикл заканчивается, i=2, поэтому все три входа имеют ссылку на последний элемент в HelpText.

2.My испытание

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

 (function() {
  function closure() {
    var i = 0;
    return {
      display: function() {
        console.log(i);
      },
      add: function() {
        i  = 1;
      }
    }
  }

  var a = closure();
  var b = closure();

  a.add();
  a.display(); //return 1
  b.display(); //return 0 
})() 

3.My мысли и вопросы

Из теста a и b имеют разные переменные i, i из a изменился, но b остался прежним. Но в цикле for все входные данные указывают на одну и ту же переменную, поэтому цикл for изменяет значение i, в результате чего все входные данные указывают на последний элемент в справочном тексте

Поэтому мой вопрос в том,почему они указывают на одну и ту же переменную, но в моем тесте a, b этого не делают.

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

1. «но в моем тесте a,b этого не делают» , потому i что определено внутри функции, но в примере MDN item определено вне обработчика событий.

2. Я действительно не понимаю, я понимаю,что onfocus-это одно из свойств элемента {…, onfocus:функция(){}} это верно ?

3. Да, функция назначается свойству, но на самом деле это не важно. Важно то, что функция обращается к свободной переменной (переменной, которая сама по себе не определена), и функция вызывается после завершения цикла. Вы добьетесь того же поведения, если переместите var i = 0; объявление за пределы closure функции.

Ответ №1:

В вашем примере вы объявляете переменную i внутри closure метода. При повторном вызове closure i в области выполнения этой конкретной функции создается новая переменная, и возвращаемый объект привязывается к этой переменной.

Попробуйте переместить объявление переменной за пределы closure функции, и вы увидите, что результат будет таким же, как в примере MDN.

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

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

2. @khuongduy354: На самом деле существует множество языков, в которых функции являются объектами первого класса . Но даже на этих языках закрытие может работать по-другому.