好吧,我不知道究竟什么是好的头衔,因为这是一个最特殊的情况,或者我是异常愚蠢的.
这就是我想要做的事情.
创建一个<meter>HTML5中新增的简单标记.主要问题是我的javascript.我试图在我的javascript中逐渐增加米标签的值.但不知何故,它不能按我想要的方式工作.
JavaScript的.
for (var i = 0; i <= 10; i++) {
var a = document.getElementById("mtr1");
setTimeout(function () {
console.log(i);
a.value = i;
}, 250);
}
Run Code Online (Sandbox Code Playgroud)
我试图每250毫秒逐渐增加仪表的值.这不会发生.相反,仪表直接跳到10.
我感兴趣的i是我在控制台中获得的价值.我得到了实例10,而不是1,2,3 ...... 10.
为什么会这样?
这是一个JavaScript闭包的经典之作.这i是对变量的实际引用,而不是它的副本.在遍历循环后,它的值为10,这就是为什么所有日志调用都将10写入日志.
这应该更好:
for (var i = 0; i <= 10; i++) {
var a = document.getElementById("mtr1");
setTimeout(function (i) {
return function() {
console.log(i);
a.value = i;
};
}(i), 250 * i);
}
Run Code Online (Sandbox Code Playgroud)
这里最内部的i是setTimeout回调参数,而不是你在循环体中声明的变量.
您应该阅读有关JavaScript中的闭包的更多信息.当变量被关闭时,它是完全相同的变量,而不是副本.由于setTimeout是异步的,整个循环在任何函数运行之前完成,因此i变量将10无处不在.
function incMtrAsync(max, delay, el) {
if (el.value++ < max) {
setTimeout(incMtrAsync.bind(null, max, delay, el), delay);
}
}
incMtrAsync(10, 250, document.getElementById("mtr1"));
Run Code Online (Sandbox Code Playgroud)
上述实现使用递归方法实现循环.每次inMtrAsync调用时,它都会检查value仪表的是否达到最大值,如果没有,则通过回调注册另一个超时.
如果你想延迟初始增量,只需将第一个调用包装在另一个超时中.
setTimeout(incMtrAsync.bind(null, 10, 250, document.getElementById("mtr1")), 250);
Run Code Online (Sandbox Code Playgroud)
没有人使用setInterval,所以这是我的解决方案(http://jsfiddle.net/Qh6gb/4/):
var a = document.getElementById("mtr1");
var i = 0;
var interval = setInterval(function () {
console.log(i);
a.value = ++i;
if (i == 10) {
clearInterval(interval);
}
}, 250);
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2298 次 |
| 最近记录: |