JS函數-我調用自己試試看

來源:互聯網
上載者:User

標籤:return   png   運算式   factorial   ext   原始碼   問題:   eof   document   

前言

最近在讀《JavaScript語言精粹》,對遞迴函式有了進一步的認識,希望總結下來:

遞迴是一種強大的編程技術,他把一個問題分解為一組相似的子問題,每一問題都用一個尋常解去解決。遞迴函式就是會直接或者間接調用自身的一種函數,一般來說,一個遞迴函式調用自身去解決它的子問題。

"漢諾塔"經典遞迴問題

"漢諾塔"是印度的一個古老傳說,也是程式設計中的經典的遞迴問題,是一個著名的益智遊戲:

  題目如下:

    塔上有三根柱子和一套直徑各不相同的空心圓盤,開始時源柱子上的所有圓盤都按從大到小的順序排列。目標是通過每一次移動一個圓盤到另一根柱子上,最終把一堆圓盤移動到目標柱子上,過程中不允許把較大的圓盤放置在較小的圓盤上;

    

尋找規律(把所有的圓盤移動到C):

  1)n(圓盤個數) == 1

    第一次:1號盤  A -> C      sum(移動次數) = 1

  2)n == 2

    第一次:1號盤 A -> B

    第二次:2號盤 A -> C

    第三次:1號盤 B -> C  sum = 3

  3)n == 3

    第一次:1號盤 A -> C

    第二次:2號盤 A -> B

    第三次:1號盤 C -> B

    第四次:3號盤 A -> C

    第五次:1號盤 B -> A

    第六次:2號盤 B -> C

    第七次:1號盤 A -> C  sum = 7

  以此類推...

  故不難發現規律,移動次數為:sum = 2^n - 1 

演算法分析(遞迴):

  把一堆圓盤從一個柱子移動另一根柱子,必要時使用輔助的柱子。可以把它分為三個子問題:

    首先,移動一對圓盤中較小的圓盤到輔助柱子上,從而露出下面較大的圓盤,

    其次,移動下面的圓盤到目標柱子上

    最後,將剛才較小的圓盤從輔助柱子上在移動到目標柱子上

   把三個步驟轉化為簡單數學問題:

    (1)     把 n-1個盤子由A 移到 B;

    (2)     把 第 n個盤子由 A移到 C;

    (3)     把n-1個盤子由B 移到 C;

  我們建立一個JS函數,當它調用自身的時候,它去處理當前正在處理圓盤之上的圓盤。最後它回一個不存在圓盤去調用,在這種情況下,它不在執行任何操作。

JavaScript原始碼實現
var hanoi = function(disc,src,aux,dst){     if(disc>0){        hanoi(disc-1,src,dst,aux);        console.log(‘ 移動 ‘+ disc +  ‘ 號圓盤 ‘ + ‘ 從 ‘ + src +  ‘ 移動到 ‘ +  dst);        hanoi(disc-1,aux,src,dst)    }}hanoi(3,‘A‘,‘B‘,‘C‘)

 

整個演算法的思路是:

  1. 將A柱子上的n-1個盤子暫時移到B柱子上
  2. A柱子只剩下最大的盤子,把它移到目標柱子C上
  3. 最後再將B柱子上的n-1個盤子移到目標柱子C上

JS遞迴函式遍曆Dom

  遞迴函式可以非常高效的操作樹形結構,在JavaScript有一種"天然的樹形結構"瀏覽器端的文件物件模型(Dom)。每次遞迴調用時處理指定樹的一小段。

/*      我們定義一個walk_the_DOM函數, 1) 它從某個指定的節點開始,按指定HTML源碼的順序,訪問樹的每個節點  2)它會調用一個函數,並依次傳遞每個節點給它,walk_the_DOM調用自身去處理每一個節點*/var walk_the_DOM = function walk( node , func ) {      func(node);        node = node.firstChild;        while (node) {           walk( node , func );           node = node.nextSibling;        }    }/*    在定義一個getElementByAttribute函數1) 它以一個屬性名稱字串和一個可選的匹配值作為參數2) 它調用walk_the_DOM,傳遞一個用來尋找節點屬性名稱的函數作為參數,匹配得節點都會累加到一個數組中*/       var getElementsByAttribute=function(att,value){        var results=[];        walk_the_DOM(document.body,function(node){                                  var actual=node.nodeType===1&&node.getAttribute(att);                                  if(typeof actual===‘string‘ &&( actual===value|| typeof value!==‘string‘)){                                        results.push(node);                                   }         });      return results;  }

 

 命名函數運算式和遞迴遞迴問題

求階乘的函數:

function factorial(num){    if(num<=1){        return 1;    }else{        return num*factorial(num-1);    }}

通過將函數factorial設定為null,使原始函數的引用只剩一個, 此時factorial已不再是函數

 

arguments.callee實現遞迴

 arguments.callee是一個指向正在執行的函數的指標,因此可以用它來實現對函數的遞迴調用

function factorial(num){    if(num<=1){        return 1;    }else{        return num*arguments.callee(num-1);    }}var anotherFactorial=factorial;factorial=null;anotherFactorial(3) //6

用arguments.callee代替函數名,可以確保無論怎樣調用函數都不會出問題。因此,在編寫遞迴函式時,使用arguments.callee總比使用函數名更保險。

但是在strict 模式下,不能通過指令碼訪問arguments.callee,訪問這個屬性會報錯

命名函數運算式實現遞迴

建立一個名為f()的命名函數運算式,然後賦值給factorial,即使把函數賦值給了另一個變數,函數的名字f仍然有效,所以遞迴調用照樣能正常完成。

這種方式在strict 模式和非strict 模式都可行。

var factorial =function f(num){    ‘use strict‘    if(num<=1){        return 1;    }else{        return num* f (num-1);    }}factorial(3)    //6var anotherFactorial=factorial;factorial=null;anotherFactorial(3)      //6

 

寫在後面

何不在別人去"堅持"的時間,試著讓自己去愛...因為喜愛,所以我們付出,但正是因為付出了,所以我們只能更愛.

大學生一枚才疏學淺,如有紕漏,還望前輩指正。

 

 

JS函數-我調用自己試試看

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.