Javascript增量不起作用

Mar*_*One 4 html javascript

好吧,我不知道究竟什么是好的头衔,因为这是一个最特殊的情况,或者我是异常愚蠢的.

这就是我想要做的事情.

创建一个<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.

为什么会这样?

小提琴

aga*_*aga 7

这是一个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)

这里最内部的isetTimeout回调参数,而不是你在循环体中声明的变量.


pla*_*alx 7

您应该阅读有关JavaScript中的闭包的更多信息.当变量被关闭时,它是完全相同的变量,而不是副本.由于setTimeout是异步的,整个循环在任何函数运行之前完成,因此i变量将10无处不在.

DEMO

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)


pax*_*162 5

没有人使用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)