1.2.3.18.了解閉包(二)

  • 應用閉包的實際案例

    1 function buildFunctions() {
    2     var arr = [];
    3     for (var int i = 0; i < 3; i++){
    4         arr.push(
    5             //Only create function
    6             function () {
    7                 console.log(i);
    8             }
    9        )
    10     }  
    11     return arr[i];
    12 }
    13 var fs = buildFunctions();
    14 //執行時會找到i
    15 //印出3
    16 fs[0]();
    17 //印出3
    18 fs[1]();
    19 //印出3
    20 fs[2]();
    • 執行程式

      • 行 1 ~ 12: 全域執行環境 (global Execution context)被建立, 並存放buildFunctions(),fs

      • 行 13: 建立新的執行環境, 待函數執行完後回傳 i =3, arr = [f0, f1, f2]

        • 行7不會被執行

        • buildFunctions 的執行環境離開執行堆, 但執行環境的記憶體還會在, 因此i, arr還在

      • 行16 ~ 20被執行, 這時候因為函數中沒有i, arr的定義, 根據範圍鍊的觀念會開始向外尋找, 此時還是找的到i, arr, 因為i, arr位於外部的記憶體位置

  • 如何正常印出i?

    • 解法1:

      • 加入行4: 因為變數j會在迴圈中, 在記憶體中建立一個新的

      1 function buildFunctions2() {
      2     var arr = [];
      3     for (var int i = 0; i < 3; i++){
      4         let j = i; //es6的語法
      5         arr.push(
      6             //Only create function
      7             function () {
      8                 console.log(i);
      9             }
      10        )
      11     }  
      12     return arr[i];
      13 }
      14 var fs2 = buildFunctions2();
      15 //執行時會找到i
      16 //印出3
      17 fs2[0]();
      18 //印出3
      19 fs2[1]();
      20 //印出3
      21 fs2[2]();
    • 解法2:

      • IIFE: 立即執行

        • 行 6 ~ 20會立即執行, 此時行7會回傳匿名函數 j的值會在迴圈執行時儲存

        • 當匿名函數執行時, 會尋找j

      1 function buildFunctions2() {
      2     var arr = [];
      3     for (var int i = 0; i < 3; i++){
      4         arr.push(
      5             (function (j) {
      6                 return function() {
      7                   console.log(j);
      8                 }
      9             }(i))
      10        )
      11     }  
      12     return arr[i];
      13 }
      14 var fs2 = buildFunctions2();
      15 //執行時會找到i
      16 //印出3
      17 fs2[0]();
      18 //印出3
      19 fs2[1]();
      20 //印出3
      21 fs2[2]();

Last updated