javascript closure (loop example)
С вопроса "Почему это не работает?" люди обычно начинают изучение замыканий.
by Yury
HTML
<div id="parent"></div>
<br><br>
<div id="parent2"></div>
CSS
.closure-div {
width: 100%;
height: 30px;
}
JavaScript
//Функция addEvents принимает массив div'ов и ставит каждому вывод своего номера на onclick.
//Для тестового примера сделаем 10 разноцветных нумерованных div'ов с разными цветами:
makeDivs("parent");
function makeDivs(parentId) {
for (var i=0; i < 10; i++) {
var j = 9-i
var div = document.createElement('div')
div.style.backgroundColor = '#'+i+i+j+j+j+i
div.className="closure-div"
div.style.color = '#'+j+j+i+i+i+j
document.getElementById(parentId).appendChild(div)
}
}
function addEvents(divs) {
for(var i=0; i < divs.length; i++) {
divs[i].innerHTML = i
divs[i].onclick = function() { alert(i) }
}
}
addEvents(document.getElementById('parent').childNodes);
//Если Вы покликаете на div'ы - они все выдают одинаковый alert.
//Такой глюк возник из-за того, что все функции div[i].onclick получают значение i из одного на всех [[scope]] внешней функции. А это значение ([[scope]].i) на момент активации onclick-обработчика равно 10 (цикл завершился как только i==10).
//Чтобы все было в порядке, в таких случаях применяют специальный прием - выделение [[scope]]. Следующая функция работает правильно. В ней все то же самое, кроме div.onclick.
function addEvents2(divs) {
for(var i=0; i < divs.length; i++) {
divs[i].innerHTML = i
divs[i].onclick = function(x) {
return function() { alert(x) }
}(i)
}
}
makeDivs("parent2");
addEvents2(document.getElementById('parent2').childNodes);
//Теперь все должно быть в порядке - каждый div дает alert на свой номер.
//Для присваивания div.onclick запускается временная функция function(x) {..}, принимающая аргумент x и возвращающая обработчик, который берет x из [[scope]] этой временной функции.
//Запись function(x) {..} используется для создания функции, и тут же (i) - для запуска с аргументом i.
//Временная функция function(x) {..} заканчивает работать тут же, оставляя в своем [[scope]] правильное значение x, равное текущей переменной i цикла.
//Когда обработчик активизируется - alert возьмет из...