JavaScript遞歸


那么什么叫遞歸呢?所謂遞歸函數就是在函數體內調用本函數。最簡單的例子就是計算階乘。0和1的階乘都會被定義為1,更大的數的階乘是通過計算1*1*...來求得的,每次增加1,直至達到要計算階乘的那個數。

遞歸的缺點:如果遞歸函數的終止條件不明確或者缺少終止條件會導致函數長時間運行,是用戶界面處於假死狀態。值得注意的是:瀏覽器對遞歸的支持熟練與JS調用棧大小直接相關,當使用太多遞歸甚至超過最大調用棧容量時,瀏覽器會報錯誤信息,各個瀏覽器對報錯的提示信息也不一樣。

下面我們先來看一下一個經典的遞歸階乘函數:

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

上面的的這個函數表面上沒有什么問題,但是以下的代碼卻可能會導致問題:

var f = test; test = null; console.log(f(2));//報錯 Uncaught TypeError: test is not a function

指向原始函數的引用就剩下一個,當調用f()函數時,而test已經不再是一個函數了,所以會導致錯誤,但是我們可以使用arguments.callee來解決這個問題。

大家都知道,arguments.callee是一個指向正在執行的函數的指針,因此可以用它來實現函數的遞歸調用,看如下代碼:

function test(num){
    if(num <= 1){
        return 1;
    }else{
        return num * arguments.callee(num-1);
    }
}

哈哈,上面的代碼是不是已經完美的解決了問題呢?

NO,NO,NO....

在嚴格模式下,不能通過腳本來訪問arguments.callee,訪問這個屬性會導致錯誤的。哎!說到這里寶寶心里也累啊,但是沒有關系,還是有方法解決的,可以使用命名函數表達式來達成相同的結果。代碼如下:

var fs = (function test(num){
    if(num <= 1){
        return 1;
    }else{
        return num * test(num-1);
    }
    //下面這兩行代碼完全不會影響運行,不信?那你可以試試
    //var f = test;
    // test = null;
});
console.log(fs(2));

 

這樣即使函數賦值給了另外一個變量,f()函數依然是有效的,所以遞歸調用能正常完成。而且這種方式在嚴格模式和非嚴格模式下都可以使用哦。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM