Closure

閉包可以保存函式內的變數,無法存函式外改變變數的值,並應用到巢狀函式內。

A couple of questions

// 函式使用外部變數,會使用最新的值嗎?
let name = "John";
function sayHi() {
  alert("Hi, " + name);
}
name = "Pete";
sayHi(); // what will it show: "John" or "Pete"?

// 函式會使用內部變數還是外部變數?
function makeWorker() {
  let name = "Pete";

  return function() {
    alert(name);
  };
}

let name = "John";

// create a function
let work = makeWorker();

// call it
work(); // what will it show? "Pete" (name where created) or "John" (name where called)?

Lexical Environment

在 JavaScript 裡,每個函式、{...}、整個程式碼都有內部物件叫 Lexical Environment。有 2 個部分

  • Environment Record 一個物件儲存所有區域變數當作屬性

  • 指向外部 lexical environment

變數只是一個 Environment Record 的屬性,取得或改變變數意思是取得或改變物件的屬性。

Function Declaration

函式在 Lexical Environment 被創造的時候就已經被宣告,變數是在執行到時才被創造。這是為什麼可以在函式宣告前使用。

Inner and outer Lexical Environment

當使用函式時,會創造 2 個 Lexical Environment, inner Lexical Environment 的屬性有帶入該函式的參數,outer Lexical Environment 有全域變數包含函式本身及用到的全域變數。當函式使用變數時,會先在內部尋找,然後尋找外部,然後是全域變數。在 "use strict" 下,變數未定億會出現錯誤,非 "use strict",會指定變數值為 undefined。

Nested functions

Environments in detail

1. 腳本開始時只有全域 Lexical Environment,裡面只有宣告 makeCounter(),所有函式宣告的時候,必然有一個隱藏的屬性 [[Environment]] 指向函式,

2. 呼叫函式的時候,創造 Lexical Environment,Environment Record 儲存區域變數,指向外部 lexical reference 被設定成 [[Environment]] 屬性的函式。

3. 執行到巢狀函式時,創造 [[Environment]] 屬性外部指向 makeCounter()。

4. makeCounter() 執行完畢,結果儲存在全域變數 counter,當 counter 被呼叫執行 return count++ 這行程式碼。

5. 雖然 makeCounter() 執行完畢,但仍有 [[Environment]] 屬性指向他,因此呼叫 counter() 時,會先創造一個空的 Lexical Environment 因為沒有參數,再來指向外部的 [[Environment]] 。

6. 呼叫 counter(),不只返回 count 值,也增加他的值。

開頭問題的解答:

Code blocks and loops, IIFE

閉包的特性可以應用在任何 {...} 上。

if

for

Code blocks

IIFE

Garbage collection

Real-life optimizations

Last updated

Was this helpful?