假设我想用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()的下一次迭代,并且在多个函数调用的堆栈帧上没有累积,因此没有实际的递归。乍一看,它的确看起来像递归,但从技术上来说并不是。

09-10 05:35
查看更多