DEV Community

SGsSY
SGsSY

Posted on

The Most Familiar Stranger - JavaScript - 閉包

分享記錄檔 YouTube

根據 MDN 的說法閉包是函式以及該函式被宣告時所在的作用域環境 ( lexical environment ) 的組合

語法作用域 ( lexical scoping )

function init() {
    let name = 'John';
    function getName() {
        return name;
    }
    getName();
}

init();   // John
Enter fullscreen mode Exit fullscreen mode

getName() 並無定義 name 這個變數,但它可以參考語法作用域的變數,因此能取用到父函式宣告的變數 name,如果父函式沒找到,它可以繼續往上找,一路找到全域變數。global 的 lexical scope 就是 null。

閉包 ( Closure )

function init() {
    let name = 'John';
    function getName() {
        return name;
    }

    return getName;
}

let doInit = init();
doInit();   // John
Enter fullscreen mode Exit fullscreen mode
function init() {
    let name = 'John';
    function getName() {
        console.log(name); // 不能在 name 被宣告前使用
        let name = 'Jay';
    }

    return getName;
}
Enter fullscreen mode Exit fullscreen mode

在函數內部捕獲和保存當前語境中的變數和狀態,並將其留存在函數外部,以便在後續的呼叫中繼續使用,即使當前作用域已經被銷毀了。

應用場景

狀態保存

function useState(initialState) {
  let state = initialState;

  function getState() {
    return state;
  }

  function setState(updatedState) {
    state = updatedState;
  }
  return [getState, setState];
}

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

count();   // 0
setCount(1);
count();   // 1
setCount(500);
count();   // 500
Enter fullscreen mode Exit fullscreen mode

模擬私有變數

function createCounter() {
  let count = 0;
  function counter() {
    count++;
    console.log(count);
  }
  return counter;
}

const counter1 = createCounter();
counter1(); // 1
counter1(); // 2
counter1(); // 3

const counter2 = createCounter();
counter2(); // 1
counter2(); // 2
counter2(); // 3
Enter fullscreen mode Exit fullscreen mode

⚠️ 閉包是很強大的功能,但過度使用容易造成記憶體流失 (memory leak)

  • 以下程式碼會依序輸出什麼呢?

    function closure() { 
        let counter = 0; 
        return () => { 
            counter++;
            console.log(counter);
        }; 
    }
    
    const counter1 = closure();
    const counter2 = closure();
    
    counter1();
    counter1();
    counter2();
    counter1();
    

    答案:1, 2, 1, 3

Speedy emails, satisfied customers

Postmark Image

Are delayed transactional emails costing you user satisfaction? Postmark delivers your emails almost instantly, keeping your customers happy and connected.

Sign up

Top comments (0)

Billboard image

Create up to 10 Postgres Databases on Neon's free plan.

If you're starting a new project, Neon has got your databases covered. No credit cards. No trials. No getting in your way.

Try Neon for Free →

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay