2014-02-15 28 views
1

好吧,我意識到這可能是很多初學者 - 對你們許多人來說這裏,但我希望有人可以用我可以包裹頭腦的方式來解釋這一點。我的問題圍繞着我所聽到的功能性JavaScript - 遞歸的基礎。我正在開展一個個人項目,併爲其中一個人找到了一個很好的用例,但我仍然不太清楚發生了什麼 - 需要通過一個可視化的方式來思考。函數JS w /遞歸函數

所以,這裏是一個例子。正在解決的問題是一個簡單的幫助函數,用於查找DOM中匹配特定標記名的下一個兄弟(假設當調用函數時傳入當前元素和標記名,即findSibling(this, 'DIV'))。

var findSibling = function(el, tagName) { 
    if (el.nextSibling.tagName === tagName.toUpperCase()) 
    return el.nextSibling; 
    else 
    return findSibling(el.nextSibling, tagName); 
} 

好的,所以這個工程!大!但是,我永遠需要在這裏降落,而這真的不該有。我試圖白板出來,我能理解最好的是,這樣的事情正在發生:

findSibling(<span>,DIV)▸findSibling(<span>,DIV)▸findSibling(<span>,DIV)▸<div>

假設我們有HTML是這樣的:

<div></div> 
<span></span> 
<span></span> 
<span></span> 
<div></div> 

誰能幫助我想像這多一點?你第一次學習這個概念時可能使用過的任何提示/技巧?我只是在尋找那個燈泡......

另外,我被卡住了一段時間的一件事是第二個返回語句。爲什麼我不能在else中調用函數?爲什麼我需要回報?看起來像它只是調用與兄弟元素的函數。

謝謝!

+0

' 說明 ' – Cilan

回答

1

先解釋你的第二個問題,讓我們重寫你的函數一點:

var findSibling = function(el, tagName) { 
    var match; 
    if (el.nextSibling.tagName === tagName.toUpperCase()) { 
     match = el.nextSibling; 
    } else { 
     match = findSibling(el.nextSibling, tagName); 
    } 
    return match; 
} 

在原始代碼兩者回報做同樣的事情,回到你要搜索的標籤。每種情況下的不同之處在於如何計算匹配。

要回答您的第一個問題,讓我們以不同的方式查看您的代碼。任何時候你有一個函數,你可以隨時用函數代碼替換函數調用,並正確替換參數。例如:

function hello(text) { 
    alert('Hello ' + text); 
} 
hello('to you.'); 

是相當於

alert('Hello to you.'); 

因此,讓我們做到這一點與您的遞歸函數:

if (el.nextSibling.tagName === tagName.toUpperCase()) 
    return el.nextSibling; 
else 
    if (el.nextSibling.nextSibling.tagName === tagName.toUpperCase()) 
     return el.nextSibling.nextSibling; 
    else 
     if (el.nextSibling.nextSibling.nextSibling.tagName === tagName.toUpperCase()) 
      return el.nextSibling.nextSibling.nextSibling; 
     else 
      etcetera... 

從這個你應該能夠看到一個遞歸函數隱藏本身就是一個循環。這也顯示了遞歸函數的危險 - 他們可以不斷地調用自己。這導致我想知道 - 如果el沒有nextSibling,您的功能會發生什麼?

+0

謝謝。我想我明白了,我很欣賞你用易懂的方式回答的時間。 – SeeMeCode

1

我所想的那麼遞歸的鏡面效果或德羅斯特效應的基礎上,如下圖:

enter image description here

其中每個級別挖深入到下一個,直到達到一個極限。在你的情況下,找到所需的標籤名稱的兄弟姐妹。

所以基本上你的基本代碼是第一張圖片,第一次遞歸是第一次。它會進一步深入到達目標。

1

任何人都可以幫我想像這更多一點嗎?您在第一次學習這個概念時可能使用過的任何提示/技巧?

也許想的迭代版本將有助於理解:

function findSibling(el, tagName) { 
    while (el = el.nextSibling) { 
    if (el.tagName == tagName.toUpperCase()) { 
     return el; 
    } 
    } 
} 

此外,有一件事我被困在一段時間是第二回 聲明。爲什麼我不能在else中調用函數?爲什麼我需要 退貨?

作爲一般規則的遞歸函數將具有遞歸調用和退出條件。定義本身是遞歸的。在你的代碼中退出條件是找到tagName

如果您不理解遞歸,那麼解釋遞歸很困難。維基百科對可視化有很好的解釋。 http://en.wikipedia.org/wiki/Recursion

編輯:看到這個問題太https://softwareengineering.stackexchange.com/questions/25052/in-plain-english-what-is-recursion

1
You call a function findSibling to find 'tag' 
    But it doesnt find tag so it calls function findSibling to find 'tag' 
     But it doesnt find tag so it calls function findSibling to find 'tag' 
      But it doesnt find tag so it calls function findSibling to find 'tag' 
       It retrns tag to its caller 
      It returns tag to its caller 
     It returns tag to its caller 
    It returns tag to its you. 
You have tag. 

我認爲你能理解最好的是正確答案,這個特殊的問題。要在嵌套的 DOM中找到某些東西只是稍微複雜一點,但它的概念相同,而且代碼幾乎相同。