[英]Recursive Function, setTimeout, and 'this' keyword in javascript
假设我想用onClick方法调用一个函数。 像这样:
<li class="inline" onclick="mve(this);" >TEMP</li>
并且我有一个JS函数,如下所示:
function mve(caller){
caller.style.position = "relative";
caller.style.left = (caller.style.left+20) +'px';
var foo = setTimeout('mve(caller)', 2000);
}
我的问题是,在初始onClick调用之后,该元素(调用者所指的元素)是不确定的。 至少这是Firebug告诉我的。
我敢肯定这是一个简单的解决方案,那么对原因以及原因的简单解释又如何呢?
另外,如果我这样运行它:
function mve(caller){
caller.style.position = "relative";
caller.style.left = (caller.style.left+20) +'px';
}
我认为该元素将在每次点击时向右移动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);
}
对于问题的第二部分, 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);
}
此功能缺少的东西是它停止重复的一种方式。 就像您现在拥有的那样,它会永远持续下去。 我可能建议传递这样的多次迭代:
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);
}
}
另外,您可能很想知道这并不是真正的递归函数。 这是因为mve()
函数调用setTimeout()
然后立即完成。 setTimeout()
在一段时间后执行mve()
的下一次迭代,并且在多个函数调用的堆栈帧上没有累积,因此没有实际的递归。 乍一看,它的确看起来像递归,但从技术上来说并不是。
第一次呼叫后,呼叫者可能超出范围。 您可以通过创建具有全局范围的变量来保留它,以保留调用方的值:
var globalCaller;
function onClickEvent(caller) {
globalCaller = caller;
mve();
}
function mve() {
globalCaller.style.position = "relative";
globalCaller.style.left = (caller.style.left+20) +'px';
var foo = setTimeout('mve()', 2000);
}
不过,这确实很丑。 通过传递li元素的ID,然后调用getElementById()来创建更简洁的代码。 或者更好的方法是使用jQuery并使用$(“#id”)语法。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.