2013-07-21 111 views
0

我的问题很简单。我使用的是内部的for循环的setTimeout,运行时 错误过程中产生曰:setTimeout产生范围错误

Uncaught TypeError: Cannot call method 'setAttribute' of undefined 

我用JavaScript的经验是超薄(我跳过的jQuery学习的缘故) ,我以为这有用我打电话给setTimeout的方式。

看看我的功能,我想知道为什么“元素”不是从匿名函数内部可用。

function hide_visable_elements() 
{ 
    // remove body EventListener 
    var body = document.getElementsByTagName("body"); 
    body[0].removeEventListener("click", hide_visable_elements, true); 

    var elements = document.getElementsByClassName("visible"); 
    for (var i = 0; i < elements.length; ++i) 
    { 
    elements[i].removeAttribute("class"); 
    setTimeout(function() { elements[i].setAttribute("class", "hidden") }, 300); 
    } 
} 
+1

您推迟的函数在循环完成后执行很长时间,此时'i === elements.length'和'elements [i]'当然是'undefined',因为它超出了边界的访问范围。 – Esailija

+0

那我该如何达到所需的延迟呢?根据你所说的话,如果我将300ms改为0ms,它应该可以工作,但不是。 –

+0

在你推迟一个函数之前,在那个时候捕获'i'的值,这样当函数最终执行时,它将使用你捕获的值而不是当前的任何'i'。这与毫秒数毫无关系,任何数量都会在循环执行后长时间执行。 – Esailija

回答

1

下面是使被执行时,它的循环完成后,你如何能捕捉迭代的电流值为例(它总是后,由于异步性质),它会做正确的事:

function setHidden(element) { 
    return function() { 
     element.setAttribute("class", "hidden"); 
    }; 
} 

function hide_visable_elements() { 
    // remove body EventListener 
    var body = document.getElementsByTagName("body"); 
    body[0].removeEventListener("click", hide_visable_elements, true); 
    var elements = document.getElementsByClassName("visible"); 
    for (var i = 0; i < elements.length; ++i) { 
     elements[i].removeAttribute("class"); 
     setTimeout(setHidden(elements[i]), 300); 
    } 
} 


顺便说一下我使用的描述比较,时间t的最小量“后长”帽子在延迟功能可能执行之前经过的时间为4或13毫秒,但循环执行时间以微秒或纳秒为单位进行测量。

+0

这种方式产生相同的错误.. –

+0

@ elad.chen确保你清除缓存,这里的工作演示http://jsfiddle.net/7yWWz/1/ – Esailija

+0

这很奇怪,我使用完全相同的代码小提琴,它不起作用。 Chrome与之前报告的错误相同。 (缓存被清除)。任何想法我在这里想念什么? –