很可能你想在这里使用递归函数而不是for循环。但是,我将解释两种方法,以防你(或其他人)坚持要用循环来完成。
对于递归函数,一般想法是调用函数一次,然后让它重复调用自身,直到完成所需操作。在代码方面,它可能看起来有点像这样:
loopThroughSplittedText: function(splittedText) {
var locationInString = 0;
function delayedOutput() {
console.log(splittedText[locationInString]);
locationInString++;
if (locationInString < splittedText.length) {
setTimeout(delayedOutput, 1000);
}
}
delayedOutput();
},
或者,如果你真的喜欢使用循环,你仍然可以这样做,但是需要进行一些调整才能实现。
首先,你需要将console.log
放在它自己的函数中。这是因为当你放置console.log(something)
时,你实际上并没有传递它,而是立即调用它,这不是你想要的;通过调用它,它会立即将文本输出到控制台,而不是等待稍后。将其放入自己的函数中允许它被传递给setTimeout,以便稍后调用。
其次,你需要将那个函数包装在另一个函数中,以确保它在触发时得到正确的i
值。原因实际上是这样的:你的意图是告诉函数“当你准备好了,使用我设置你时的i
值。”但是,你现在正在做的实际上是说“当你准备好了,看看i
”。因为该函数直到准备好触发时才检查i
的值,所以它不会知道其值,直到你执行循环之后很久,这意味着i
将是一个比你想要的数字高得多的数字!
作为上述的一个子要点,你需要立即调用那个函数。这称为立即调用的函数表达式。如果你不熟悉它们,它们肯定值得一看。它们的用途有点不寻常,但在正确的位置使用它们是一个强大的工具。
最后,因为你正在此处设置所有内容,所以要确保每个函数的超时间隔为一秒钟;现在,你正在说“从现在开始一秒钟内完成所有这些操作”,而你的意图是“从现在开始,每隔一秒钟完成所有这些操作”。这个修复相对容易;你只需要将你的超时乘以i
,这样你就可以设置第一个在1秒后启动,第二个在2秒后启动,依此类推。
所有这些组合起来,给你的代码看起来像这样:
loopThroughSplittedText: function(splittedText) {
for (var i = 0; i < splittedText.length; i++) {
setTimeout(
(function(locationInString) {
return function() {
console.log(splittedText[locationInString]);
};
}(i)),
(1000*i)
);
}
},
关于哪种解决方案更好,我可能会推荐使用递归函数。递归版本将仅创建一个函数,为您传递的每个字符串调用自身,而for循环版本将为字符串中的每个字符创建一个函数,这可能会非常快速地失控。在JavaScript中,函数创建(以及对象创建)在处理较大项目时可能会变得昂贵,因此通常最好倾向于避免在可能的情况下创建大量函数的解决方案。
但是,出于解释的目的,我不想让您没有for循环版本的知识;在其他地方,这些知识可能也会派上用场。 :)
setTimeout
的问题,但似乎OP立即调用而不是将函数作为第一个参数传递。 - Qantas 94 Heavy