我的函数应该迭代文档中的所有表单,并将onclick函数绑定到表单中的每个'calculate'元素。问题是,在任何点击事件上执行的函数在循环中的最后一个i的上下文中执行。
以下是我正在使用的JavaScript:
window.onload = function(){
calculateSavings();
}
function calculateSavings(){
for (i = 0; i < document.forms.length; i++) {
var e = document.forms[i];
e.calculate.onclick = function() {
var hours = e.hours.value;
var rate = e.rate.value;
alert(hours * rate);
}
}
}
这是附加到的HTML:
<!doctype html>
<html>
<body>
<form>
<label for="hours">Hours: </label><input type="text" id="hours" name="hours">
<label for="rate">Rate: </label><input type="text" id="rate" name="rate">
<input type="button" name="calculate" value="Calculate">
<div id="savings"></div>
</form>
<form>
<label for="hours">Hours: </label><input type="text" id="hours" name="hours">
<label for="rate">Rate: </label><input type="text" id="rate" name="rate">
<input type="button" name="calculate" value="Calculate">
<div id="savings"></div>
</form>
</body>
</html>
我确信这是一个非常基本的问题,但解决方案在这一点上完全无法解决。
以下是我遇到的问题的演示:http://jsfiddle.net/KcNWy/
答案 0 :(得分:4)
你有闭包循环问题。请参阅,我不知道,this或由同一个问题引起的大约一百万个其他SO问题。
i
和e
每次循环都是相同的变量:循环只会更改i
和e
,它不会给你一个新的{{ 1}}。因此,当e
触发,在循环完成迭代很久之后,function() { ... }
将保留其最终值,即最后一个匹配的输入。
(另外,你还没有声明e
,所以var i
比这更糟糕,这是偶然的全球性。)
它的典型方法是在闭包中添加另一个函数作用域以在创建时保留值的副本:
i
您可以使用e.elements.calculate.onclick = function(e) {
return function() {
var hours = e.elements.hours.value;
var rate = e.elements.rate.value;
alert(hours * rate);
}
}(e);
方法在ECMAScript第五版中更干净地完成:
Function#bind
但这意味着adding support此方法适用于尚不支持它的现有浏览器。
或者将闭包放在循环机制本身可以避免这个问题:
e.elements.calculate.onclick = function(e) {
var hours = this.elements.hours.value;
var rate = this.elements.rate.value;
alert(hours * rate);
}.bind(e);
或者,每次只使用相同的函数并从点击的元素中获取表单引用:
forEach(document.forms, function(form) {
form.elements.calculate.onclick = function() {
var hours = form.elements.hours.value;
var rate = form.elements.rate.value;
alert(hours * rate);
}
});
function forEach(list, callback) {
for (var i= 0, n= list.length; i<n; i++)
callback(list[i]);
}
答案 1 :(得分:0)
您是否可以使用“this”在onclick函数中引用而不是使用“e”?