T11*_*110 1 javascript recursion this settimeout
假设我想用onClick方法调用一个函数.像这样:
<li class="inline" onclick="mve(this);" >TEMP</li>
Run Code Online (Sandbox Code Playgroud)
我有一个JS函数,如下所示:
function mve(caller){
caller.style.position = "relative";
caller.style.left = (caller.style.left+20) +'px';
var foo = setTimeout('mve(caller)', 2000);
}
Run Code Online (Sandbox Code Playgroud)
我的问题是在初始onClick调用之后,元素(调用者引用的)是未定义的.至少这是Firebug告诉我的.
我确信这是一个简单的解决方案,那么如何简单解释为什么以及如何解释?
如果我像这样运行它:
function mve(caller){
caller.style.position = "relative";
caller.style.left = (caller.style.left+20) +'px';
}
Run Code Online (Sandbox Code Playgroud)
我认为元素在每次点击时都会移动20px,但情况并非如此.思考?
setTimeout()在全局范围内执行字符串参数,因此您的值this不再存在,也不是您的参数caller.这是不使用setTimeout的字符串参数的众多原因之一.使用像这样的实际javascript函数引用,解决相关传递的参数是一个非常容易的问题:
function mve(caller){
caller.style.position = "relative";
caller.style.left = (caller.style.left+20) +'px';
setTimeout(function() {
mve(caller)
}, 2000);
}
Run Code Online (Sandbox Code Playgroud)
对于你的问题的第二部分,caller.style.left将会有这样的单位,20px当你添加20它,你得到20px20,这不是一个浏览器将理解的值,所以没有任何反应.您将需要解析其中的实际数字,将数字加20,然后重新添加单位,如下所示:
function mve(caller){
caller.style.position = "relative";
caller.style.left = (parseInt(caller.style.left), 10) +20) + 'px';
setTimeout(function() {
mve(caller)
}, 2000);
}
Run Code Online (Sandbox Code Playgroud)
此功能缺少的东西是它停止重复的一种方式.正如你现在所拥有的那样,它会永远持续下去.我可能会建议传递这样的迭代次数:
function mve(caller, iterationsRemaining){
caller.style.position = "relative";
caller.style.left = (parseInt(caller.style.left), 10) +20) + 'px';
if (--iterationsRemaining) > 0) {
setTimeout(function() {
mve(caller, iterationsRemaining)
}, 2000);
}
}
Run Code Online (Sandbox Code Playgroud)
此外,您可能很想知道这不是一个真正的递归函数.那是因为mve()函数调用setTimeout()然后立即完成.它是setTimeout()在mve()一段时间之后执行下一次迭代,并且在多个函数调用的堆栈帧上没有累积,因此没有实际的递归.从一瞥代码看起来确实像递归,但在技术上并非如此.