繁体   English   中英

递归函数,setTimeout和javascript中的'this'关键字

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM