Published on

面試經典題-閉包

Authors
  • avatar
    Name
    Yufu
    Twitter

閉包

閉包是指在一個內部函數中可以訪問到其外部函數的變量或參數,即使外部函數已經返回。簡單來說,閉包是一個函數和該函數所在環境的集合。

閉包的用途

就不吊人胃口,先上code

const counterModule=()=> {
  let count = 0;

  const increment=()=> {
    count++;
  }

  const decrement=()=> {
    count--;
  }

  const getCount=()=> {
    return count;
  }

  return {
    increment: increment,
    decrement: decrement,
    getCount: getCount
  };
}

let counter = counterModule();

counter.increment();
counter.increment();
console.log(counter.getCount()); //輸出2

counter.decrement();
console.log(counter.getCount()); //輸出1

以上例子中定義一個counterModule函數,這個函數內定義三個私有函數incrementdecrementgetCount,它們都可以訪問私有變量count。

創建變量counter接counterModule返回值,再根據需求調用模塊中的方法進行交互。

這演示了閉包最常見的基礎應用,就是私有變量的封裝,將變量封裝在函式內部,防止外部代碼訪問修改。另外,上述例子中,counterModule內將多個函數及變量包在同一個作用域中,形成一個獨立的模塊,從而提高代碼可維護性及可重用性。

接著來看看常見的閉包題目吧!

第一題

function baseCounter() {
  let count = 0;

  return function () {
    return count++;
  };
}

let counter = baseCounter();

console.log(counter())
console.log(counter())
console.log(counter())

結果:控制台會打印 0、1、2

第二題

for (var i = 0; i < 5; i++) {
  setTimeout(function() {
    console.log(i);
  }, 1000);
} //控制台會打印 5個 5

如果要我們用學到的閉包修改以上代碼,讓控制台打印結果為0、1、2、3、4的話,應該怎麼做呢?

結果:

for (var i = 0; i < 5; i++) {
    (function(j){
      setTimeout(function() {
        console.log(j);
      }, 1000);
    })(i)
}

透過每次回圈中的i值當作參數傳遞給立即執行函式,將參數儲存在回調函數的作用域中,此時執行setTimeout時所打印的j就會是各自內部的j值

閉包可以說是非常見的面試考題,想想上次求職時閉包就被問了兩次,可見其重要性,每次面試都要讀一次閉包的相關知識,故在這邊做個紀錄,如果文章內容有誤還望讀者多多指教,今天就先到這裡~