1. 程式人生 > >遞迴和閉包的理解

遞迴和閉包的理解

閉包以及遞迴

在我們平時的工作可能遞迴用的不是很多,閉包可能我們在不經意間就使用了,所以建議大家有必要的去了解一下。

        遞迴指函式自己呼叫自己。

        當然我們在使用遞迴時也要注意一些問題:

  1. 自己呼叫自己就相當於迴圈一樣,以此來到達一些便利;

  2.   我們在使用遞迴時必須要有跳出的條件,不然就會出現死遞迴;

  3. 遞迴在計算的時候會極大的消耗計算機的效能,在計算的值比較小的時候我們可以忽略,當我們使用遞迴需要迴圈的值比較大的時候,我們就不得不考慮其的計算效率,那將是一個比較龐大的計算量

        下面通過幾個例子來給大家講解一下普通的遞迴:

   1.  求兔子序列(斐波那契數列)的前幾項;

var fib = function ( n ) {
   if ( n === 0 || n === 1 ) return 1;
   return fib( n - 1 ) + fib( n - 2 );
};

    2.  求n^m次方;   

function fn(a,b){
   if(b==0)return 1;
   return fn(a,b-1)*a;
}

    3.   求等差數列前幾項的和;       

function fn(n) {
    if (n == 1)return 1;
    return fn(n - 1) + (2 * n - 1)
}

        在操作遞迴時,遞迴會把自己引數中的值進行傳遞,直到我們傳遞的值達到我們設定的跳出條件時才會停止傳遞,而後面的公式指的是與我們需要得到的值進行的相對應操作,當我們寫在函式中的值就相當於每一個傳遞的實參。

       但是是遞迴的效能消耗又是我們不得不重視的,那麼下面通過對於資料的快取來給大家介紹一下如何讓遞迴減少效能的消耗。

通過上述的程式碼我們可以使遞迴在計算時減少很大一部分的效能消耗。

        閉包指的被函式分割而成的作用域,從而形成的被保護的私有資料,這個就被我們稱之為閉包。

        我們要做的就是通過一些辦法來得到閉包內部的資料。

        下面給大家講解一下閉包:

function foo() {
   var num = Math.random();
   return num;
}

var res = foo();  
var r1 = foo();
var r2 = foo();

        正常我們覺得從函式中reture出來的值是一樣的,當我們列印隨機數時,我們會發現值其實是不相同的。只是我們平時在使用閉包的時候,return得到的值是同一個,所以會誤認為得到的值是同一個。其實是值不會改變而已。

        下面給大家說一下解決的辦法:

function func() {
   var n = Math.random();
   var m = Math.random();
   return { 
      get_N: function () { return n; },
      get_M: function () { return m; }
   };
}
var o = func();

var n = o.get_N();
var m = o.get_M();

       o接收的是在函式func中return出來的物件,所以呼叫o就是在呼叫return出來的物件。

所以我們得到的是物件中的函式通過作用域鏈查詢的上一級的值,然後進行儲存,只有作用域鏈被破壞掉時,才會重新獲得資料。

        下面是通過閉包和遞迴實現的帶有快取的斐波那契數列


      閉包的優點是毋容置疑的,減少對於全域性變數的汙染,在內部形成一個保護資料的私有空間。我們需要得要資料時必須使用一些特殊的方法才可以訪問內部的資料,這樣可以很大的保護我們存在於閉包中的資料。

        比如我們可以利用沙箱模式來進行處理資料的保護,留下一個特定的方法來可以進行訪問,其他方法無效,我們也可以在沙箱中的回撥函式中傳入document或者dody,window等減少計算機的查詢次數。從而減少對於效能的消耗。

(function (w){
   
   function fun() {};
   
   fun.prototype.extend = function (){};
   
   w.I = window.itcast = fun;
   
})(window||document);