2013-07-25 20 views
3

我有一个超时,调用一个函数,直到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); 
} 

回答

1

的问题是,内部func使用的可变i在SCOP之外创建这个函数,并在每次迭代中增加。然后,当您最后拨打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); 
} 
+0

你能解释为什么'j = i;'修复它吗?我不明白区别 – Sir

+0

@Oriol - 你的分号应该是var语句中的逗号。 – dc5

+0

@ dc5我修复了他:) – Sir

1

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

首先,我介绍将封装你想要的对象;它被用杆构件和函数初始化当它这样做数到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()函数的上下文。

完成后,它会调用完成功能,传入对象在其上运行的元素。

完成的功能是容易得多,如果你传递的元素删除:

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

现在是非常简单的;它会创建一个新的对象并调用其run()方法。完成:)

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

Demo