函数接收未定义的值

时间:2013-07-25 01:08:21

标签: javascript

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

我不确定代码在哪个阶段丢失了传递的值,从而使其返回undefined但是我已经制作了一个JS小提琴,它可以让你看到它:

JS Fiddle

我的最终结果是接收正确的值然后删除给定的元素,如下所示:

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);
}

2 个答案:

答案 0 :(得分:1)

问题是i内部使用的变量func是在该函数范围之外创建的,并且在每次迭代时都会增加。然后,当您在结束时致电func时,i等于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);
}

答案 1 :(得分:1)

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

首先,我正在介绍将封装你想要的东西的对象;它被初始化为一个bar元素和一个函数,当它被计数到100时调用。因此,我将它称为BarCounter

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

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

这只是构造函数;它没有做任何有用的事情;它解析了text元素,它只是它在给定元素下面可以找到的第一个<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()方法。完成:))

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

Demo