首頁 > web前端 > js教程 > 主體

JavaScript中遞迴函數的解析與說明

黄舟
發布: 2017-11-18 10:28:58
原創
2193 人瀏覽過

我們之前先跟大家介紹過關於php中的遞迴函數、其實遞迴函數通常在後端用的比較多。對於後端開發人員來說,遞迴應該是小菜一碟,很簡單的事情,但是很多前端確實對這個不是很了解。其實,前端中也是常用遞迴的,今天我們就來給大家解析下JavaScript中的遞迴函數!

js遞歸呼叫

// 一个简单的阶乘函数  var f = function (x) {  
    if (x === 1) {  
        return 1;  
    } else {  
        return x * f(x - 1);  
    }  };
登入後複製

Javascript中函數的巨大靈活性,導致在遞歸時使用函數名稱遇到困難,對於上面的變數聲明,f是一個變量,所以它的值很容易被替換:

var fn = f;  f = function () {};
登入後複製

函數是個值,它被賦給fn,我們期待使用fn(5)可以計算出一個數值,但是由於函數內部仍然引用的是變數f,於是它不能正常工作了。

所以,一旦我們定義了一個遞歸函數,便須注意不要輕易改變變數的名字。

上面談論的都是函數式調用,函數還有其它調用方式,例如當作物件方法調用。

我們常常這樣宣告物件:

var obj1 = {  
    num : 5,  
    fac : function (x) {  
        // function body  
    }  };
登入後複製

宣告一個匿名函數並且把它賦值給物件的屬性(fac)。

如果我們想要在這裡寫一個遞歸,就要引用屬性本身:

var obj1 = {  
    num : 5,  
    fac : function (x) {  
        if (x === 1) {  
            return 1;  
        } else {  
            return x * obj1.fac(x - 1);  
        }  
    }  };
登入後複製

當然,它也會遭遇和函數呼叫方式一樣的問題:

var obj2 = {fac: obj1.fac};  
obj1 = {};  
obj2.fac(5); // Sadness
登入後複製

方法被賦值給obj2的fac屬性後,內部仍要引用obj1.fac,於是…失敗了。

換個方式會有所改進:

var obj1 = {  
     num : 5,  
     fac : function (x) {  
        if (x === 1) {  
            return 1;  
        } else {  
            return x * this.fac(x - 1);  
        }  
    }  };  var obj2 = {fac: obj1.fac};  obj1 = {};  obj2.fac(5); // ok
登入後複製

透過this關鍵字取得函數執行時的context中的屬性,這樣執行obj2.fac時,函數內部便會引用obj2的fac屬性。

可是函數還可以被任意修改context來調用,那就是萬能的call和apply:

obj3 = {};  obj1.fac.call(obj3, 5); // dead again
登入後複製

於是遞歸函數又不能正常運作了。

我們應該試著解決這個問題,還記得前面提到的一種函數宣告的方式嗎?

var a = function b(){};
登入後複製

這種宣告方式叫做內聯函數(inline function),雖然在函數外沒有宣告變數b,但是在函數內部,是可以使用b()來呼叫自己的,於是

var fn = function f(x) {  
    // try if you write "var f = 0;" here  
    if (x === 1) {  
        return 1;  
    } else {  
        return x * f(x - 1);  
    }  };  
    var fn2 = fn;  fn = null;  fn2(5); // OK  // here show the difference between "var f = function f() {}" and "function f() {}"  var f = function f(x) {  
    if (x === 1) {  
        return 1;  
    } else {  
        return x * f(x - 1);  
    }  };  var fn2 = f;  f = null;  fn2(5); // OK  var obj1 = {  
    num : 5,  
    fac : function f(x) {  
        if (x === 1) {  
            return 1;  
        } else {  
            return x * f(x - 1);  
        }  
    }  };  var obj2 = {fac: obj1.fac};  obj1 = {};  obj2.fac(5); // ok  var obj3 = {};  obj1.fac.call(obj3, 5); // ok
登入後複製

就這樣,我們有了一個可以在內部使用的名字,而不用擔心遞歸函數被賦值給誰以及以何種方式被呼叫。

Javascript函數內部的arguments對象,有一個callee屬性,指向的是函數本身。因此也可以使用arguments.callee在內部呼叫函數:

function f(x) {  
    if (x === 1) {  
        return 1;  
    } else {  
        return x * arguments.callee(x - 1);  
    }  }
登入後複製

但arguments.callee是一個已經準備被棄用的屬性,很可能會在未來的ECMAscript版本中消失,在ECMAscript 5中"use strict"時,不能使用arguments.callee。

最後一個建議是:如果要宣告一個遞歸函數,請慎用new Function這種方式,Function建構子所建立的函式在每次被呼叫時,都會重新編譯出一個函數,遞歸呼叫會引發效能問題——你會發現你的記憶體很快就被耗光了。

js遞迴函數應用程式

最近在做專案的時候,用到了遞迴函數,用來呼叫json的子節點,把所有json中的子節點包含某個數的object ,都push到一個數組中,然後對其進行綁定。

我是透過如下遞歸呼叫的

var new_array=[];
     function _getChilds(data){
         if(data.ObjType=="某个数"){
            new_array.push(cs_data);
        }
        if(data.Childs){
          if(data.Childs.length>0){
              getChilds(data.Childs)
          }
       }
     }
    function getChilds(data){
        for(var i=0;i<data.length;i++){
            _getChilds(data[i]);
        }
    }使用方法:getChilds("json数据")
登入後複製

就把json中所有包含某個數的資料push到new_array陣列當中了。

總結:

相信透過對上述的講解,大家對遞迴函數的認識更進階一步、遞迴函數不只可以再在php中使用,在前端JavaScript中同樣可以使用,希望對你有幫助!

相關推薦:

#JavaScript中遞歸函數的細化認識以及範例程式碼分享

JS中遞迴函數

#js中遞迴函數的使用介紹

以上是JavaScript中遞迴函數的解析與說明的詳細內容。更多資訊請關注PHP中文網其他相關文章!

相關標籤:
來源:php.cn
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板