Я предпочитаю, чтобы прослушиватели событий были развернуты модульной функцией, а не сценарием прослушивателя событий уровня document
. Итак, мне нравится ниже. Обратите внимание: вы не можете переадресовать элемент с одним и тем же прослушивателем событий, поэтому не беспокойтесь о прикреплении слушателя более одного раза - только один палец.
var iterations = 4;
var button;
var body = document.querySelector("body");
for (var i = 0; i < iterations; i++) {
button = document.createElement("button");
button.classList.add("my-button");
button.appendChild(document.createTextNode(i));
button.addEventListener("click", myButtonWasClicked);
body.appendChild(button);
}
function myButtonWasClicked(e) {
console.log(e.target); //access to this specific button
}
Вложенная функция ищет переменные из родительской области при выполнении, а не когда определено.
Тело функции скомпилировано, а «свободные» переменные (не определенные в самой функции путем назначения) проверяются, а затем привязываются как замыкающие ячейки к функции, причем код использует индекс для ссылки на каждую ячейку. pet_function
, таким образом, имеет одну свободную переменную (cage
), которая затем ссылается через ячейку замыкания, индекс 0. Сама замыкание указывает на локальную переменную cage
в функции get_petters
.
Когда вы на самом деле вызываете функцию, это закрытие затем используется для просмотра значения cage
в окружающем пространстве во время вызова функции . Здесь кроется проблема. К тому моменту, когда вы вызываете свои функции, функция get_petters
уже выполняется, вычисляя ее результаты. Локальная переменная cage
в какой-то момент во время этого выполнения была назначена каждой из строк 'cow'
, 'dog'
и 'cat'
, но в конце функции cage
содержит это последнее значение 'cat'
. Таким образом, когда вы вызываете каждую из динамически возвращаемых функций, вы получаете значение 'cat'
.
Обход - это не полагаться на замыкания. Вместо этого вы можете использовать частичную функцию , создать новую область функций или привязать переменную как значение по умолчанию для параметра ключевого слова .
functools.partial()
: from functools import partial
def pet_function(cage=None):
print "Mary pets the " + cage.animal + "."
yield (animal, partial(gotimes, partial(pet_function, cage=cage)))
def scoped_cage(cage=None):
def pet_function():
print "Mary pets the " + cage.animal + "."
return pet_function
yield (animal, partial(gotimes, scoped_cage(cage)))
def pet_function(cage=cage):
print "Mary pets the " + cage.animal + "."
yield (animal, partial(gotimes, pet_function))
Нет необходимости определять функцию scoped_cage
в цикле, компиляция выполняется только один раз, а не на каждом итерация цикла.
Это проистекает из следующего
for i in range(2):
pass
print i is 1
после того, как итерирование значения i
лениво сохранено в качестве его окончательного значения.
В качестве генератора функция будет работать (т. е. печатать каждое значение по очереди), но при преобразовании в список он запускается через генератор, поэтому все вызовы cage
(cage.animal
) возвращают кошек.
Мое понимание заключается в том, что клетка просматривается в пространстве имен родительских функций, когда вызываемая функция pet_function фактически вызывается, а не раньше.
Итак, когда вы делаете
funs = list(get_petters())
Вы генерируете 3 функции, которые найдут последнюю созданную клетку.
Если вы замените свой последний цикл на:
for name, f in get_petters():
print name + ":",
f()
Фактически вы получите:
cow: Mary pets the cow.
dog: Mary pets the dog.
cat: Mary pets the cat.