4

我有一个超时,它调用一个函数,直到 100% 进度完成。然后它执行我分配给它的功能。只有赋予它的值是未定义的或至少是它的一部分。

我不确定代码在哪个阶段丢失了正在传递的值,从而使其返回undefined,但我已经制作了一个 JS Fiddle 以供您查看:

JS小提琴

我的最终结果是接收正确的值,然后像这样删除给定的元素:

function rmv_div(div_id) {
   //div_id is not properly defined so cannot find the div.
    document.getElementById('result').innerHTML = div_id;
    var div = document.getElementById(div_id);
    div.parentNode.removeChild(div);
}
4

2 回答 2

1

i问题是内部使用的变量func是在该函数范围之外创建的,并且在每次迭代时都会增加。然后,当您func最后调用时,iequals array.length,所以array[i]未定义。

您可以解决它在每次迭代中创建另一个不会增加的变量:

解决方案 1

演示http://jsfiddle.net/qJ42h/4/ http://jsfiddle.net/qJ42h/11/

for (var i = 0; i < array.length; i++) {
    var bar = document.getElementById('bar' + array[i]),
        text = document.getElementById('text' + array[i]),
        remove = 'wrap' + array[i],
        j = i;
    do_something(bar, text, function () {
        rmv_div('id' + array[j]);
    }, 1);

}

解决方案 2

演示http://jsfiddle.net/qJ42h/8/ http://jsfiddle.net/qJ42h/12/

for (var i = 0; i < array.length; i++) {
    var bar = document.getElementById('bar' + array[i]),
        text = document.getElementById('text' + array[i]),
        remove = 'wrap' + array[i];
    do_something(bar, text, (function(i) {
        return function(){ rmv_div('id' + array[i]); }
    })(i), 1);
}
于 2013-07-25T01:14:57.630 回答
1

这里的问题是您没有隔离i闭包内的循环变量。然而,这可以通过使用对象更优雅地解决。

首先,我将介绍封装您想要的对象的对象;它使用一个 bar 元素和一个在计数到 100 时调用的函数进行初始化。所以,我将调用它BarCounter

function BarCounter(element, fn)
{
    this.element = element;
    this.fn = fn;

    this.text = element.getElementsByTagName('div')[0];
    this.counter = 0;
}

这只是构造函数;它没有做任何有用的事情;它解析文本元素,这只是<div>它可以在给定元素下找到的第一个标签,并存储该引用以供以后使用。

现在我们需要一个可以完成这项工作的函数;让我们称之为run()

BarCounter.prototype.run = function()
{
    var that = this;

    if (this.counter < 100) {
        this.text.innerHTML = this.counter++;

        setTimeout(function() {
            that.run();
        }, 70);
    } else {
        this.fn(this.element);
    }
}

该函数将检查计数器是否已达到 100;在那之前,它将使用当前值更新文本元素,增加计数器,然后在 70 毫秒后再次调用自身。您可以看到如何预先保留对的引用以this保留run()稍后调用函数的上下文。

完成后,它调用完成函数,传入BarCounter对象操作的元素。

如果您传递要删除的元素,完成功能会容易得多:

function removeDiv(element)
{
    element.parentNode.removeChild(element);
}

最后一步是调整其余代码:

var array = [1];
for (var i = 0; i < array.length; ++i) {
    var bar = new BarCounter(
        document.getElementById('bar' + array[i]), 
        removeDiv
    );
    bar.run();
}

现在很简单;它创建一个新BarCounter对象并调用其run()方法。完毕 :)

顺便说一句,您也可以选择从对象中删除元素;当然,这取决于您自己的需要。

演示

于 2013-07-25T02:56:57.203 回答