2016-06-30 2 views
5

В documentation for the let statement in MDN, есть этот пример код:Как переменные, определенный с помощью `let` действует внутри` for` петли

var list = document.getElementById("list"); 

for (let i = 1; i <= 5; i++) { 
    let item = document.createElement("li"); 
    item.appendChild(document.createTextNode("Item " + i)); 

    item.onclick = function (ev) { 
    console.log("Item " + i + " is clicked."); 
    }; 
    list.appendChild(item); 
} 

Затем они заявляют:

В приведенном выше примере работ по назначению потому что пять экземпляров внутренней функции (анонимный) относятся к пяти различным экземплярам переменной i.

Я не понимаю, почему есть «пять различных экземпляров переменной i.

Первое заявление в for цикла всегда выполняется один раз, нет? Так let оператор должен выполнять только один раз ...
После того, как код достигает конца итерации он проверяет состояние во втором сообщении.

Каким образом, согласно тому, что они пишут, что есть новый экземпляр i на каждой итерации?

+0

Не то, о чем вы просите, но на прошлой неделе мне удалось проверить это поведение и обнаружил, что IE не реализовал его должным образом (Chrome сделал.) – nnnnnn

+1

В спецификации ECMA 6, когда выражение let каждая итерация создает новую лексическую область, привязанную к предыдущей области. http://www.ecma-international.org/ecma-262/6.0/#sec-for-statement-runtime-semantics-labelled_оценка –

+0

Чтобы понять это , измените это 'let' на' var' и посмотрите, что происходит, когда вы нажимаете на элементы, созданные в цикле – Jamiec

ответ

3

Когда выражение let используется, каждая итерация создает новую лексическую область, прикованную к предыдущей области видимости.

Это означает, что каждое закрытие захватывает другой экземпляр.

Это соответствует ECMA 6 specification, но не уверен, что он будет работать одинаково во всех браузерах.

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

+0

Прежде чем 'let' IIFEs были использованы в чтобы добиться такого же эффекта - возможно, даже хуже. Итак, какова ваша рекомендация? – ftor

+0

@ LUH3417 Я просто говорю, что я не уверен в производительности такой конструкции в разных браузерах. Например, посмотрите на эту проблему, указанную для хрома https://bugs.chromium.org/p/v8/issues/detail?id=4762 –

+0

@ LUH3417 и да, возможно, iffy-s еще хуже с точки зрения производительности , Поэтому я не рекомендую вообще ничего рекомендовать –

0

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

Если вы объявляете переменную с помощью var где-нибудь в вашей функции (например, в цикле), то он будет объявлен только один раз в верхней части рамки благодаря hoisting, и там будет только один экземпляр его во всей области действия.

Это может привести к проблемам при вызове обратных вызовов внутри цикла for ....

// with hoisting, i is only declared once 
for (var i in items) { 
    // the fn is called items.length times, before any callback is invoked 
    _fetchItems(items[i], function() { 
     console.log("fetched for ", items{i]); 
     // for all callbacks, i is the same value items.length-1 
     // because they are called after the loop is complete 
    }); 
} 

Или в вашем примере:

// with hoisting, i is only declared once 
for (var i = 1; i <= 5; i++) { 

    // with hoisting, item is only declared once 
    var item = document.createElement("li"); 
    item.appendChild(document.createTextNode("Item " + i)); 

    // this function will be called after the for...loop is complete 
    // so i value is unique: 5 + 1 = 6 
    item.onclick = function (ev) { 
     // => always return "Item 6 is clicked" 
     console.log("Item " + i + " is clicked."); 
    }; 
    list.appendChild(item); 
} 

На противоположном, let переменных только область видимости до ближайшего блока (т.е. любого кода раздела между фигурными скобками.).

В вашем примере новый экземпляр переменной i объявлен для каждого выполнения блока внутри цикла for .... i идет от 1 до 5, поэтому есть 5 исполнений блока, следовательно, 5 экземпляров переменной.

Они будут возвращать ожидаемое значение «Пункт 1 щелкнут»., «Пункт 2 щелкнут.»и т. д.

+0

Дело в том, что первый оператор в цикле 'for' всегда выполняется один раз. , сделав это следующим образом: for (var i = 1; i ++; i <5) {let t = i; ...} 'не вызывает вопросов. –

 Смежные вопросы

  • Нет связанных вопросов^_^