2012-04-17 81 views
1

假設我想用onClick方法調用函數。就像這樣:javascript中的遞歸函數,setTimeout和'this'關鍵字

<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的權利,但事實並非如此。思考?

回答

4

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()的下一次迭代,並且多個函數調用的棧幀沒有累積,因此沒有實際的遞歸。它看起來像從代碼的一瞥遞歸,但不是技術上。

+0

謝謝。這不僅回答了我的問題,而且額外的洞察力和清晰的表達使材料易於消化;非常感謝。 – T110 2012-04-17 12:23:01

0

在第一次通話後,主叫方可能會超出範圍。你可以通過創建一個全局範圍的變量來保存它,以保留來電者的值:

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」)語法。

+0

清潔工根據jfriend00的回答使用封口。 – RobG 2012-04-17 02:20:38