iT邦幫忙

2024 iThome 鐵人賽

DAY 12
0
佛心分享-刷題不只是刷題

30 天克服前端面試系列 第 12

Day 12 - 請說明 closure 閉包是什麼?如何應用?

  • 分享至 

  • xImage
  •  

閉包是什麼?

closure 函式可以存取其外部函式的變數,即使外部函式已經執行完畢並離開其作用域。可以存取到外部變數的原因在於: JavaScript 使用了語法作用域(lexical scope),在函式定義時會記住函式被定義時的變數環境,並且這些變數會一直存在於記憶體中,只要閉包中的內部函式仍然在使用它們。

當外部函式執行完畢後,通常會釋放其作用域中的變數以節省記憶體。但如果某個內部函式(閉包)仍然引用這些變數,那麼這些變數將不會被釋放,而是持續存在於內部函式的作用域鏈中。

function outerFunction() {
  let outerVariable = "I am outside!";

  function innerFunction() {
    console.log(outerVariable);
  }

  return innerFunction;
}

const closureFunction = outerFunction();
closureFunction(); // I am outside!
  • 內部函式 innerFunction 是閉包,它記住了 outerFunction 的語法作用域,它可以存取到外部變數 outerVariable,即使 outerFunction 已經執行完畢。

閉包的應用

資料封裝

閉包可以用來模擬私有變數,使得外部無法直接存取某些變數,只能透過內部函式進行操作。

function createCounter() {
  let count = 0;

  return function () {
    count++;
    console.log(count);
  };
}

const counter = createCounter();
counter(); // 1
counter(); // 2

count 只能透過 counter 函式來來增加或減少值,外部無法直接存取。

模擬私有方法和變數

閉包可以用來模擬類似於物件中的私有變數和方法。

function counter() {
  let count = 0;

  function increment() {
    count++;
  }

  function decrement() {
    count--;
  }

  function getCount() {
    return count;
  }

  return {
    increment,
    decrement,
    getCount,
  };
}
const teamACounter = counter();
teamACounter.increment();
teamACounter.increment();
teamACounter.decrement();
console.log(teamACounter.getCount()); // 1
const teamBCounter = counter();
teamBCounter.increment();
teamBCounter.increment();
console.log(teamBCounter.getCount()); // 2

在這個例子中,count 變數是私有的,外部無法直接存取,只能透過 incrementdecrementgetCount 這三個方法來操作。
同時可以透過閉包的特性,創建多個獨立的 Counter,互不影響。

事件處理(Event handlers)和回呼函式(Callbacks)

閉包經常應用於事件處理或回呼函式中,特別是當需要保持一些狀態或變數時。
React 中的 useState 就是應用了閉包的特性。

import React, { useState } from "react";

const Button = () => {
  const [count, setCount] = useState(0);

  const handleClick = () => {
    setCount((prevCount) => prevCount + 1);
    console.log(`Button clicked ${count} times`);
  };

  return <button onClick={handleClick}>Click me</button>;
};

在這個例子中,handleClick 函式是閉包,每次點擊按鈕都會增加 count 變數的值。


實例練習

99. closure

let dev = "bfe";

function a() {
  let dev = "BFE";
  return function () {
    console.log(dev);
  };
}

dev = "bigfrontend";

a()();

解題

答案是"BFE",因為 a() 函式是閉包,它記住了 a 函式被定義時的變數環境,即 dev 為 "BFE"。


本文同步於此


上一篇
Day 11 - 請說明 JavaScript 中.call 和 .apply 的差異為何?
下一篇
Day 13 - 請描述原型繼承如何在 JavaScript 運作中?
系列文
30 天克服前端面試30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言