ν¨μκ° μ μΈλ λ μλμΌλ‘ μμ±λλ λ μ컬 νκ²½μ λν μ€λͺ
μ΄λ€.
μ‘°κΈ λ νμ΄μ μ€λͺ
ν΄λ³΄λ©΄
μλ°μ€ν¬λ¦½νΈμμ ν¨μλ λ¨μν μ½λ λ©μ΄λ¦¬κ° μλλΌ, κ·Έ ν¨μκ° λ§λ€μ΄μ§ λ μ£Όλ³ νκ²½(μ€μ½ν)μ΄ λ§λ€μ΄μ§κ³ μ΄ μ£Όλ³ νκ²½μ "λ μ컬 μ€μ½ν(lexical scope)"λΌκ³ λΆλ₯Έλ€. ν¨μκ° μ΄λμ μ μΈλμλμ§μ λ°λΌ μ κ·Όν μ μλ λ³μλ€μ΄ κ²°μ λλλ°
ν΄λ‘μ λ λ°λ‘ μ΄ λ μ컬 μ€μ½νλ₯Ό νμ©ν΄μ, μΈλΆ ν¨μκ° μ€νμ λ§μΉκ³ μ¬λΌμ§ λ€μλ λ΄λΆ ν¨μκ° κ·Έ μΈλΆ ν¨μμ λ³μμ μ κ·Όν μ μκ² λ§λλ κ²μ΄λ€. μλ₯Ό λ€μ΄μ, ν΄λ‘μ λ μλμ κ°μ΄ μλνλ€.
ν΄λ‘μ λ λ°λ‘ μ΄ λ μ컬 μ€μ½νλ₯Ό νμ©ν΄μ, μΈλΆ ν¨μκ° μ€νμ λ§μΉκ³ μ¬λΌμ§ λ€μλ λ΄λΆ ν¨μκ° κ·Έ μΈλΆ ν¨μμ λ³μμ μ κ·Όν μ μκ² λ§λλ κ²μ΄λ€. μλ₯Ό λ€μ΄μ, ν΄λ‘μ λ μλμ κ°μ΄ μλνλ€.
π μΈλΆν¨μ λ΄λΆμ ν¨μκ° μ‘΄μ¬νλ μμ
function greetMaker(name) { let greeting = "μλ , " + name + "!"; // μΈλΆ ν¨μμ λ³μ function sayHello() { console.log(greeting); // λ΄λΆ ν¨μμμ μΈλΆ λ³μ μ¬μ© } return sayHello; // λ΄λΆ ν¨μ λ°ν } const greetToMin = greetMaker("λ―Όμ"); // "μλ , λ―Όμ!"κ° μ μ₯λ¨ greetToMin(); // "μλ , λ―Όμ!" μΆλ ₯
μμ½λ μμ greetMakerκ° μ€νμ λλ΄λ©΄ μΌλ°μ μΌλ‘ greeting λ³μλ μ¬λΌμ§ κ² κ°μ§λ§, ν΄λ‘μ λλΆμ sayHelloκ° κ·Έ λ³μλ₯Ό κ³μ κΈ°μ΅νκ³ μλ€. κ·Έλμ greetToMin()μ νΈμΆνλ©΄ "μλ
, λ―Όμ!"κ° μΆλ ₯λλ κ²μ΄λ€.
ν΄λ‘μ μ λ©μ§ μ μ μ΄λ° νΉμ±μ νμ©ν΄μ λ°μ΄ν°λ₯Ό 보νΈνκ±°λ, νΉμ μνλ₯Ό μ μ§νλ λ° μ¬μ©ν μ μλ€λ μ μ΄ μλ€..
function createCounter() { let count = 0; return function() { count += 1; return count; }; } const counter = createCounter(); console.log(counter()); // 1 console.log(counter()); // 2 console.log(counter()); // 3
μ¬κΈ°μ countλ createCounter ν¨μ λ°μμλ μ κ·Όν μ μμ§λ§, λ°νλ ν¨μκ° ν΄λ‘μ λ‘ countλ₯Ό κΈ°μ΅νκ³ μμ΄μ κ°μ κ³μ μ¦κ°μν¬ μ μμ£ . μ΄λ° μμΌλ‘ ν΄λ‘μ λ κ°μΈμ μΈ κ³΅κ°μ λ§λ€μ΄μ£Όλ μν μ νλ€.
μ¦, ν΄λ‘μ λ ν¨μμ κ·Έ ν¨μκ° μ κ·Όν μ μλ νκ²½μ΄ ν¨κ» λ¬Άμ¬μ, μ μ°νλ©΄μλ κ°λ ₯ν μ½λλ₯Ό μμ±ν μ μκ² ν΄μ£Όλ μλ°μ€ν¬λ¦½νΈμ ν΅μ¬ κΈ°λ₯ μ€ νλμ΄λ€.
μ€ν 컨ν μ€νΈμ λ μ컬 μ€μ½ν
λ¨Όμ , μ€ν 컨ν
μ€νΈλ μλ°μ€ν¬λ¦½νΈ μ½λκ° μ€νλ λ λ§λ€μ΄μ§λ νκ²½μ΄λ€. μ΄ νκ²½μλ
- λ³μ κ°μ²΄(variable object)
- μ€μ½ν 체μΈ(scope chain)
- κ·Έλ¦¬κ³ this κ°
κ°μ μ λ³΄κ° ν¬ν¨λΌ μλ€. ν¨μκ° νΈμΆλ λλ§λ€ μλ‘μ΄ μ€ν 컨ν
μ€νΈκ° μμ±λλλ°, μ΄κ±΄ μ€ν ννλ‘ μμ¬μ νμ¬ μ€ν μ€μΈ μ½λμ κ·Έ μ£Όλ³ νκ²½μ κ΄λ¦¬νλ€.
μ¬κΈ°μ μ€μν 건 λ μ컬 μ€μ½νμΈλ° λ μ컬 μ€μ½νλ ν¨μκ° μ΄λμ μ μΈλμλμ§μ λ°λΌ κ·Έ ν¨μκ° μ κ·Όν μ μλ λ³μμ λ²μκ° μ ν΄μ§λ€. μ¦, ν¨μκ° μμ±λ μμΉμ λ°λΌ "μ μ μΌλ‘" μ€μ½νκ° κ²°μ λλ€λ λ»μ΄λ€. μ΄ λ μ컬 μ€μ½νλ μ€ν 컨ν
μ€νΈκ° λ§λ€μ΄μ§ λ ν¨μμ νκ²½μ κΈ°μ΅νλ λ° ν΅μ¬μ μΈ μν μ νλ€.
μ€μ½νμ μ€μ½ν 체μΈ
μ€μ½νλ μ΄λ€ λ³μμ μ κ·Όν μ μλ μ ν¨λ²μλ‘ μ½λ μ΄λμλ μ°Έμ‘° ν μ μλ μ μμ€μ½νμ ν¨μμμ κ³Ό νμν¨μμμλ§ μ°Έμ‘°ν μ μλ μ§μμ€μ½νκ° μλ€. ν¨μ μμμ μ μΈλ λ³μλ ν΄λΉ ν¨μμμλ§ μ¬μ©ν μ μμΌλ©° μ μλ³μμ μν₯μ λΌμΉ μ μλ€.
μμμ λ§ν μ€μ½ν 체μΈμ ν¨μκ° μ μΈλ λ μ컬 μ€μ½νλ₯Ό κΈ°λ°μΌλ‘, λ³μμ μ κ·Όν λ λ°λΌκ°λ μΌμ’
μ "νμ κ²½λ‘"μ΄λ€. μλ°μ€ν¬λ¦½νΈλ λ΄λΆ ν¨μμμ μ°Έμ‘°ν λ³μκ° νμ¬ μ€μ½νμ μμΌλ©΄, κ·Έ μμ μ€μ½νλ‘ λ²μλ₯Ό λν κ°λ©° μ°Ύμ μ¬λΌκ°λλ° μ€ν 컨ν
μ€νΈ μμ μ μ₯λ μ€μ½ν 체μΈμ΄ λ°λ‘ μ΄ κ³Όμ μ κ°λ₯νκ² ν΄μ€λλ€.
ν΄λ‘μ μ νμ
ν΄λ‘μ λ λ΄λΆ ν¨μκ° μΈλΆ ν¨μμ λ³μμ μ κ·Όνλ μν©μμ λνλλ€. μΈλΆ ν¨μκ° μ€νμ λ§μΉκ³ μ€ν 컨ν
μ€νΈκ° μ€νμμ μ κ±°λλλΌλ, λ΄λΆ ν¨μλ μΈλΆ ν¨μμ λ μ컬 νκ²½μ μ°Έμ‘°ν μ μλ€.
μ΄κ² κ°λ₯ν μ΄μ λ λ΄λΆ ν¨μκ° μ€μ½ν 체μΈμ ν΅ν΄ μΈλΆ ν¨μμ λ³μκ° μ μ₯λ νκ²½μ κ³μ "κΈ°μ΅"νκ³ μκΈ° λλ¬Έμ΄κ³ μλ°μ€ν¬λ¦½νΈ μμ§μ λ³μλ ν¨μκ° μ΄λ€ μ€μ½νμμ μ¬μ ν μ°Έμ‘°λκ³ μλ κ²½μ°, κ·Έ λ°μ΄ν°λ₯Ό λ©λͺ¨λ¦¬μμ μ κ±°νμ§ μκ³ μ μ§νλλ‘ μ€κ³λμ΄ μλ€.
κ°λΉμ§ 컬λ μ κ³Ό μ°Έμ‘°
μλ°μ€ν¬λ¦½νΈ μμ§(μ: V8 μμ§ κ°μ κ²½μ°)μλ κ°λΉμ§ 컬λ ν°(Garbage Collector, GC)κ° μμ΄μ λ μ΄μ μ¬μ©λμ§ μλ λ©λͺ¨λ¦¬λ₯Ό μ 리ν΄μ€λ€. κ°λΉμ§ 컬λ ν°λ κΈ°λ³Έμ μΌλ‘ "λλ¬ κ°λ₯μ±(reachability)"μ΄λΌλ κ°λ
μ κΈ°μ€μΌλ‘ λμνλ€.
- μ΄λ€ λ°μ΄ν°κ° μ½λμμ λ μ΄μ λλ¬(μ°Έμ‘°)λ μ μμΌλ©΄, κ·Έ λ°μ΄ν°λ λ©λͺ¨λ¦¬μμ ν΄μ (garbage collected)λ λμμ΄ λλ€.
- λ°λλ‘, μ΄λ€ λ°μ΄ν°κ° μ¬μ ν μ°Έμ‘°λκ³ μμΌλ©΄ λ©λͺ¨λ¦¬μ μ μ§λλ€.
ν΄λ‘μ μ κ²½μ°, λ΄λΆ ν¨μκ° μΈλΆ ν¨μμ λ μ컬 νκ²½μ μ€μ½ν 체μΈμ ν΅ν΄ μ°Έμ‘°νκ³ μμΌλ©΄, κ·Έ λ μ컬 νκ²½κ³Ό κ·Έ μμ μλ λ³μλ€μ "λλ¬ κ°λ₯"ν μνλ‘ κ°μ£Όλλ€. κ·Έλμ κ°λΉμ§ 컬λ ν°κ° μ΄ λ©λͺ¨λ¦¬λ₯Ό μ 리νμ§ μκ³ λ¨κ²¨λλ€.
function outer() { let x = 10; function inner() { console.log(x); } return inner; } const closure = outer(); closure(); // 10 μΆλ ₯
- μ¬κΈ°μ outerκ° λλ νμλ closure λ³μκ° inner ν¨μλ₯Ό μ°Έμ‘°νκ³ μλ€.
- innerλ μ€μ½ν 체μΈμ ν΅ν΄ outerμ λ μ컬 νκ²½(κ·Έ μμ x = 10 ν¬ν¨)μ μ°Έμ‘°νκ³ μλ€.
- μλ°μ€ν¬λ¦½νΈ μμ§μ closureκ° μ΄μμλ ν, innerκ° μ°Έμ‘°νλ xμ κ·Έ λ μ컬 νκ²½μ΄ λλ¬ κ°λ₯νλ€κ³ νλ¨ν΄μ λ©λͺ¨λ¦¬μμ μ κ±°νμ§ μλλ€.
λ μ컬 νκ²½
π λ μ컬 νκ²½μ κ΅¬μ± μμ
- νκ²½ λ μ½λ(Environment Record): λ³μ, ν¨μ μ μΈ, λ§€κ°λ³μ λ±μ΄ μ μ₯λ¨.
- μΈλΆ λ μ컬 νκ²½ μ°Έμ‘°(Outer Reference): μμ μ€μ½νμ λ μ컬 νκ²½μ κ°λ¦¬ν΄.
π μ€μ½ν 체μΈ(Scope Chain)κ³Ό λ μ컬 νκ²½
- μ€μ½ν 체μΈμ λ μ컬 νκ²½μ΄ μ§μ κ°μ§κ³ μλ 건 μλκ³ λ μ컬 νκ²½μ "μΈλΆ μ°Έμ‘°"λ₯Ό ν΅ν΄ μ€μ½ν 체μΈμ΄ λ§λ€μ΄μ§λ€.
- μ€μ½ν 체μΈμ μ€ν 컨ν μ€νΈκ° μ€νλ λ, νμ¬ λ μ컬 νκ²½κ³Ό κ·Έ μΈλΆ μ°Έμ‘°λ₯Ό μ°κ²°νλ©΄μ νμ±λλ λμ μΈ μ²΄μΈμ΄λΌκ³ λ³Ό μ μλ€. μ¦, λ μ컬 νκ²½μ μ€μ½ν μ²΄μΈ μ체λ₯Ό "κ°μ§κ³ μλ€"κ³ ννν기보λ€λ "μ€μ½ν 체μΈμ κ°λ₯νκ² νλ ꡬ쑰"μ΄λ€.
π λ μ컬 μ€μ½ν(Lexical Scope)μ λ μ컬 νκ²½
- λ μ컬 νκ²½μ ν¨μκ° μ μΈλ μμΉμ λ°λΌ μ μ μΌλ‘ κ²°μ λλ©° ν¨μκ° μ μΈλ λ κ·Έ μ£Όλ³ νκ²½μ μΊ‘μ²ν΄μ λ μ컬 μ€μ½νλ₯Ό λ§λ λ€.
π this κ°κ³Ό μ€ν컨ν μ€νΈ
- μ€ν 컨ν μ€νΈλ λ μ컬 νκ²½(Lexical Environment), λ³μ κ°μ²΄(Variable Object), κ·Έλ¦¬κ³ this λ°μΈλ©μ ν¬ν¨νλ λ μ컬 νκ²½λ³΄λ€ λ ν° κ΅¬μ‘°μ΄λ€. λ μ컬 νκ²½μ κ·Έ μμμ λ³μμ μ€μ½νλ§ λ€λ£¨κ³ , thisλ ν¨μκ° "μ΄λ»κ² νΈμΆλμλμ§"μ λ°λΌ λμ μΌλ‘ κ²°μ νλ€.
π μμ λ‘ νμΈ
function outer() { let x = 10; function inner() { console.log(x, this); } return inner; } const closure = outer.call({ name: "test" }); closure(); // 10, { name: "test" } κ°μ Έμ€μ§λ§, μ΄κ±΄ λ μ컬 νκ²½μ΄ thisλ₯Ό ν¬ν¨ν΄μκ° μλλΌ νμ΄ν ν¨μ μ체μ νΉμ± λλ¬Έμ΄λ€.
λ μ컬 νκ²½
- outerμ λ μ컬 νκ²½: { x: 10, inner: ν¨μ }, μΈλΆ μ°Έμ‘°λ μ μ.
- innerμ λ μ컬 νκ²½: λ‘컬 λ³μ μμ, μΈλΆ μ°Έμ‘°λ outerμ λ μ컬 νκ²½.
μ€μ½ν 체μΈ
- inner μ€ν μ inner β outer β μ μμΌλ‘ μ°κ²°.
this
- outer.callλ‘ { name: "test" }κ° λ°μΈλ©λ¨. μ΄κ±΄ λ μ컬 νκ²½μ΄ μλλΌ μ€ν 컨ν μ€νΈμμ κ²°μ .