Это классическая проблема привязки петли-переменной. См. этот вопрос для обсуждения.
Ваше закрытие неэффективно, потому что оно закрывается поверх копии changer
, используемой внутри цикла, который изменится цикл. Чтобы связать его, вам нужно другое закрытие, чтобы взять копию текущей версии changer
:
function changebind(c) {
return function() {
c.change(c);
};
}
for (var i=0; i<3; i++) {
var changer= new TextChanger(i);
changer.textNode.addEventListener('click', changebind(changer), false);
(Вы можете отказаться от аргумента node
и просто использовать this
.)
В будущем (пятое издание ECMAScript) будет более быстрый и эффективный способ сказать это:
for (var i=0; i<3; i++) {
var changer= new TextChanger(i);
changer.textNode.addEventListener('click', changer.change.bind(changer), false);
changer.doneButton.addEventListener('click', changer.changeBack.bind(changer), false);
}
но тем временем, поскольку большинство браузеров пока не поддерживают function.bind
, вы можете взломать это следующим образом:
if (!Object.bind) {
Function.prototype.bind= function(owner) {
var that= this;
var args= Array.prototype.slice.call(arguments, 1);
return function() {
return that.apply(owner,
args.length===0? arguments : arguments.length===0? args :
args.concat(Array.prototype.slice.call(arguments, 0))
);
};
};
}