Javascript增量不起作用

时间:2013-11-06 13:08:56

标签: javascript html

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

这就是我想要做的事情。

创建一个简单的<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);
}

我试图每250毫秒逐渐增加仪表的值。这不会发生。相反,仪表直接跳到10。

我感兴趣的是我在控制台中获得的i的价值。我得到10的实例,而不是1,2,3 ... 10。

为什么会这样?

FIDDLE

9 个答案:

答案 0 :(得分: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);
}

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

答案 1 :(得分: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"));

上述实现使用递归方法实现循环。每次调用inMtrAsync时,它都会检查仪表的value是否达到最大值,如果没有,则通过回调注册另一个超时。

如果你想延迟初始增量,只需将第一个调用包装在另一个超时中。

setTimeout(incMtrAsync.bind(null, 10, 250, document.getElementById("mtr1")), 250);

答案 2 :(得分: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);

答案 3 :(得分:3)

您描述的问题发生在原始版本中对setTimeout的异步调用看到10的{​​{1}}值之前,因为这是执行回调时的值。

所以,这是关闭范围的一个问题,为了使它工作你应该像这样:

i

另外,由于for (var i = 0; i <= 10; i++) { var a = document.getElementById("mtr1"); (function (i, a) { setTimeout(function () { console.log(i); a.value = i; }, 250); })(i, a); } 始终相同,因此应该更好:

a

如果那时你想看到计数器“勾选”,这将使其可见:

var a = document.getElementById("mtr1");
for (var i = 0; i <= 10; i++) {
    (function (i) {
        setTimeout(function () {
          console.log(i);
          a.value = i;
        }, 250);
    })(i);
}

请参阅http://jsfiddle.net/LDt4d/

答案 4 :(得分:2)

这是因为您调用了setTimeout,这是“异步”。因此setTimeout被调用10次,但是在完成整个循环之后它被执行。因此,每次通话i = 10 ......

http://jsfiddle.net/Qh6gb/9/

有解决方案:

var i = 1,
    meter = document.getElementById("mtr1");

function increase() {
    meter.value = i++;
    console.log(i);
    if(i<=10) {
        setTimeout(increase, 250);
    }
}

setTimeout(increase, 250);

答案 5 :(得分:1)

你可以使用timeout jquery插件: 更容易

但是你应该计算你的超时,

对你而言,timeout=250*max=250*10=2500

所以

$('meter').timeout(2500);

Demo

答案 6 :(得分:0)

在函数内部运行for循环,而不是在循环的每一步中声明一个闭包。

JSFIDDLE: http://jsfiddle.net/Qh6gb/3/

var a = document.getElementById("mtr1");
setTimeout(function () {      
    for (var i = 0; i < 10; i++) {
        console.log(i);
        a.value = i;
    }
}, 250);

答案 7 :(得分:0)

我希望我理解正确。如果你有解决方案,请试着告诉我。

var count = 0;
function increment(){
    document.getElementById("meter").value = count; 
    count++; 
    if(count ==10) 
        count=0;
}
setInterval(increment, 250);

请查看jsFiddle

答案 8 :(得分:-1)

您正在创建多个同时被启动的功能。 将计时器乘以i以获得正确的延迟。

for (var i = 0; i <= 10; i++) {
var a = document.getElementById("mtr1");
setTimeout(function () {
    console.log(i);
    a.value = i;
}, 250 * i);
}