开发者问题收集

未捕获的 RangeError:超出最大调用堆栈大小和未捕获的 TypeError

2016-03-09
3106

我有这个函数

function flicker(length) {
    $("p:nth-child(" + (Math.random() * length) + ")").toggleClass('off');
    setTimeout(flicker(length), Math.random()*1000);
}

上面的代码给了我错误

Uncaught RangeError: Maximum call stack size exceeded

我还想知道当我使用

document.querySelectorAll("p:nth-child(" + (Math.random() * length) + ")").classList.toggle('off');

时是否有任何方法可以用 JavaScript 切换类,我得到了错误

Uncaught TypeError: Cannot read property 'toggle' of undefined

我该如何解决这些问题?

谢谢。

3个回答

调试后,我发现了 2 个问题。

  1. Math.random() * length 返回一个浮点数,因此需要四舍五入。
  2. setTimeout 可以在延迟后通过传递 length 参数来接受函数

window.setTimeout(func, [delay, param1, param2, ...]);

function flicker(length) {
  $("p:nth-child(" + Math.round(Math.random() * length) + ")").toggleClass('off');
  setTimeout(flicker, Math.random() * 1000, length);
}

flicker(5)
.off {
  color: white;
  font-weight: bold;
  background-color: black
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<p>1</p>
<p>2</p>
<p>3</p>
<p>4</p>
BenG
2016-03-09

使用 setTimout 时,必须将 flicker(length) 包装在一个函数中,如下所示:

function flicker(length) {
  $("p:nth-child(" + (Math.random() * length) + ")").toggleClass('off');
  setTimeout(function(){flicker(length);}, Math.random()*1000);
}

否则,它总是会立即被调用,导致如下结果:

function foo(){
  foo();
}
foo();

这只会创建一个无限循环,并会导致与您描述的相同的堆栈错误。

Michael Kunst
2016-03-09

出现此问题的原因是您在无限循环中调用 flicker() ,将其结果设置为 setTimeout ,而不是传递其引用。您需要为 setTimeout() 调用提供一个匿名函数。试试这个:

function flicker(length) {
    $("p:nth-child(" + (Math.random() * length) + ")").toggleClass('off');
    setTimeout(function() {
        flicker(length)
    }, Math.random()*1000);
}
Rory McCrossan
2016-03-09