1. 程式人生 > 其它 >js閉包和遞迴

js閉包和遞迴

技術標籤:jsjavascript

js的閉包和遞迴

1閉包

1.1什麼是閉包
定義一:閉包是一個有權訪問另一個函式作用域中變數的函式,也就是說閉包是一個函式,當然這個一般是內部函式作用域訪問外部函式作用域

定義二:一個函式和對其周圍狀態(lexical environment,詞法環境)的引用捆綁在一起(或者說函式被引用包圍),這樣的組合就是閉包,這個定義中閉包仍然被看成一個函式,只不過需要結合函式的詞法環境才可以被稱作閉包

特點:
1閉包是一個函式
2內部函式使用了外部函式的變數

1.2閉包的作用
作用:延伸變數的作用範圍
函式在執行時,會生成一個作用域,作用域中包含了函式內部定義或者使用的變數,函式執行完畢後,作用域消失,其中的變數自然無法使用(函式的生命週期問題)

但由於閉包的存在,使得 outer 函式執行完畢後,其內部變數 n 仍然被保留

function outer(){
     var n=100
     function inner(){
         console.log(n);
     }
     return inner
 }
var fn=outer() // outer 函式執行完畢,其內部變數應該銷燬,但由於 inner 函式使用了此變數給,所以此變數一直被保留
fn()
function makeAdder(x){
    return function(y){
        // console.log(x,y);
        return
x+y } } var add5=makeAdder(5) var add10=makeAdder(10) add5(2) add10(2)

1.3閉包的案例
利用閉包的方式得到當前li 的索引號

for (var i = 0; i < lis.length; i++) {
// 利用for迴圈建立了4個立即執行函式
// 立即執行函式也成為小閉包因為立即執行函式裡面的任何一個函式都可以使用它的i這變數
(function(i) {
    lis[i].onclick = function() {
      console.log(i);
    }
 })(i);
}

閉包應用-3秒鐘之後,列印所有li元素的內容

 for (var i = 0; i < lis.length; i++) {
   (function(i) {
     setTimeout(function() {
     console.log(lis[i].innerHTML);
     }, 3000)
   })(i);
}

閉包應用-計算打車價格

/*需求分析
打車起步價13(3公里內),  之後每多一公里增加 5塊錢.  使用者輸入公里數就可以計算打車價格
如果有擁堵情況,總價格多收取10塊錢擁堵費*/

 var car = (function() {
     var start = 13; // 起步價  區域性變數
     var total = 0; // 總價  區域性變數
     return {
       // 正常的總價
       price: function(n) {
         if (n <= 3) {
           total = start;
         } else {
           total = start + (n - 3) * 5
         }
         return total;
       },
       // 擁堵之後的費用
       yd: function(flag) {
         return flag ? total + 10 : total;
       }
    }
 })();
console.log(car.price(5)); // 23
console.log(car.yd(true)); // 33

2.遞迴

2.1什麼是遞迴
遞迴:如果一個函式在內部可以呼叫其本身,那麼這個函式就是遞迴函式。簡單理解:函式內部自己呼叫自己, 這個函式就是遞迴函式

注意:遞迴函式的作用和迴圈效果一樣,由於遞迴很容易發生“棧溢位”錯誤(stack overflow),所以必須要加退出條件return。

2.2利用遞迴求1~N的階乘

//利用遞迴函式求1~n的階乘 1 * 2 * 3 * 4 * ..n
 function fn(n) {
     if (n == 1) { //結束條件
       return 1;
     }
     return n * fn(n - 1);
 }
 console.log(fn(3));//執行結果為:6

2.3利用遞迴求裴波那契數列

// 利用遞迴函式求斐波那契數列(兔子序列)  1、1、2、3、5、8、13、21...
// 使用者輸入一個數字 n 就可以求出 這個數字對應的兔子序列值
// 我們只需要知道使用者輸入的n 的前面兩項(n-1 n-2)就可以計算出n 對應的序列值
function fb(n) {
  if (n === 1 || n === 2) {
        return 1;
  }
  return fb(n - 1) + fb(n - 2);
}
console.log(fb(3));

2.4利用遞迴遍歷資料

// 我們想要做輸入id號,就可以返回的資料物件
 var data = [{
   id: 1,
   name: '家電',
   goods: [{
     id: 11,
     gname: '冰箱',
     goods: [{
       id: 111,
       gname: '海爾'
     }, {
       id: 112,
       gname: '美的'
     },

            ]

   }, {
     id: 12,
     gname: '洗衣機'
   }]
 }, {
   id: 2,
   name: '服飾'
}];
//1.利用 forEach 去遍歷裡面的每一個物件
 function getID(json, id) {
   var o = {};
   json.forEach(function(item) {
     // console.log(item); // 2個數組元素
     if (item.id == id) {
       // console.log(item);
       o = item;
       return o;
       // 2. 我們想要得裡層的資料 11 12 可以利用遞迴函式
       // 裡面應該有goods這個陣列並且陣列的長度不為 0 
     } else if (item.goods && item.goods.length > 0) {
       o = getID(item.goods, id);
     }
   });
   return o;
}