ν΄λ‘μ (closure)λ λν΄νκΈ°λ‘ μ λͺ ν μλ°μ€ν¬λ¦½νΈμ κ°λ μ€ νλλ‘ MDN μμλ λ€μκ³Ό κ°μ΄ μ μνλ€.
β A closure is the combination of a function and the lexical environment within which that function was declared.β
ν΄λ‘μ λ ν¨μμ κ·Έ ν¨μκ° μ μΈλ λ μ컬 νκ²½κ³Όμ μ‘°ν©μ΄λ€.
μ μ μμ ν΅μ¬ ν€μλλ βν¨μκ° μ μΈλ λ μ컬 νκ²½β μ΄λ€.
μλ°μ€ν¬λ¦½νΈ μμ§μ ν¨μλ₯Ό μ΄λμ νΈμΆνλμ§κ° μλλΌ ν¨μλ₯Ό μ΄λμ μ μνλμ§μ λ°λΌ μμ μ€μ½νλ₯Ό κ²°μ νλ€. μ΄λ₯Ό λ μ컬 μ€μ½ν(μ μ μ€μ½ν)λΌ νλ€.
λ μ컬 μ€μ½ν κ°λ μ΄ κ°λ₯νλ €λ©΄ ν¨μλ μμ μ΄ νΈμΆλλ νκ²½κ³Όλ μκ΄μμ΄ μμ μ΄ μ μλ νκ²½, μ¦ μμ μ€μ½ν(ν¨μ μ μκ° μμΉνλ μ€μ½νκ° λ°λ‘ μμ μ€μ½νλ€)λ₯Ό κΈ°μ΅ν΄μΌ νλ€. μ΄λ₯Ό μν΄ ν¨μλ μμ μ λ΄λΆ μ¬λ‘― [[Environment]]μ μμ μ΄ μ μλ νκ²½, μ¦ μμ μ€μ½νμ μ°Έμ‘°λ₯Ό μ μ₯νλ€.
μ΄ λ μμ μ λ΄λΆ μ¬λ‘― [[Environment]]μ μ μ₯λ μμ μ€μ½νμ μ°Έμ‘°λ νμ¬ μ€ν μ€μΈ μ€ν 컨ν
μ€νΈμ λ μ컬 νκ²½μ κ°λ¦¬ν¨λ€. λν μμ μ΄ νΈμΆ λμμ λ μμ±λ ν¨μ λ μ컬 νκ²½μ βμΈλΆ λ μ컬 νκ²½μ λν μ°Έμ‘°βμ μ μ₯λ κ°μ΄λ€.
const x = 1;
// β
function outer() {
const x = 10;
const inner = function () { console.log(x); }; // β‘
return inner;
}
// outer ν¨μλ₯Ό νΈμΆνλ©΄ μ€μ²© ν¨μ innerλ₯Ό λ°ννλ€.
// κ·Έλ¦¬κ³ outer ν¨μμ μ€ν 컨ν
μ€νΈλ μ€ν 컨ν
μ€νΈ μ€νμμ νλμ΄ μ κ±°λλ€.
const innerFunc = outer(); // β’
innerFunc(); // β£ 10
μ μ½λμμ outer ν¨μλ₯Ό νΈμΆνλ©΄ outerν¨μλ innerλ₯Ό λ°ννκ³ μλͺ μ£ΌκΈ°λ₯Ό λ§κ°νλλ° μ΄ λ outer ν¨μμ μ§μ λ³μ x λν μλͺ μ£ΌκΈ°λ₯Ό λ§κ°νλ€. κ·Έλ¬λ μ μ½λλ₯Ό μ€ννλ©΄ outer ν¨μμ μ§μλ³μ xκ°μΈ 10μ΄ λμνλλ° μ΄λ₯Ό ν΄λ‘μ λΌκ³ νλ€.
ν΄λ‘μ λ μΈλΆ ν¨μλ³΄λ€ μ€μ²© ν¨μκ° λ μ€λ μ μ§λλ κ²½μ° μ€μ²© ν¨μλ μ΄λ―Έ μλͺ μ£ΌκΈ°κ° μ’ λ£ν μΈλΆ ν¨μμ λ³μλ₯Ό μ°Έμ‘°ν μ μλ€. μ΄λ¬ν μ€μ²© ν¨μλ₯Ό ν΄λ‘μ (closure) λΌκ³ λΆλ₯Έλ€.
μλ°μ€ν¬λ¦½νΈμ λͺ¨λ ν¨μλ μμ μ μμ μ€μ½νλ₯Ό κΈ°μ΅νλ€κ³ νλ€. λͺ¨λ ν¨μκ° κΈ°μ΅νλ μμ μ€μ½νλ ν¨μλ₯Ό μ΄λμ νΈμΆνλ μκ΄μμ΄ μ μ§λλ€. λ°λΌμ ν¨μλ₯Ό μ΄λμ νΈμΆνλ μκ΄μμ΄ ν¨μλ μΈμ λ μμ μ΄ κΈ°μ΅νλ μμ μ€μ½νμ μλ³μλ₯Ό μ°Έμ‘°ν μ μμΌλ©° μλ³μμ λ°μΈλ© λ κ°μ λ³κ²½ν μλ μλ€.
μ μ½λμμ outer ν¨μμ μ€νμ΄ μ’ λ£νλ©΄ outer ν¨μμ μ€ν 컨ν μ€νΈλ μ€ν 컨ν μ€νΈ μ€νμμ μ κ±°λμ§λ§ outer ν¨μμ λ μ컬 νκ²½κΉμ§ μλ©Ένλ κ²μ μλλ€.
outer ν¨μμ λ μ컬 νκ²½μ inner ν¨μμ [[Environment]] λ΄λΆ μ¬λ‘―μ μν΄ μ°Έμ‘°λκ³ μκ³ inner ν¨μλ μ μλ³μ innerFuncμ μν΄ μ°Έμ‘°λκ³ μμΌλ―λ‘ κ°λΉμ§ 컬λ μ λμμ΄ λμ§ μκΈ° λλ¬Έμ΄λ€. κ°λΉμ§ 컬λ ν°λ λκ΅°κ°κ° μ°Έμ‘°νκ³ μλ λ©λͺ¨λ¦¬ 곡κ°μ ν¨λΆλ‘ ν΄μ νμ§ μλλ€.
μ€μ²© ν¨μ inner λ μΈλΆ ν¨μ outer λ³΄λ€ λ μ€λ μμ‘΄νκ³ , μ΄ λ μΈλΆ ν¨μλ³΄λ€ λ μ€λ μμ‘΄ν μ€μ²© ν¨μλ μΈλΆ ν¨μμ μμ‘΄ μ¬λΆ(μ€ν 컨ν μ€νΈμ μμ‘΄ μ¬λΆ)μ μκ΄ μμ΄ μμ μ΄ μ μλ μμΉμ μν΄ κ²°μ λ μμ μ€μ½νμ μλ³μλ₯Ό μ°Έμ‘°ν μ μκ³ μλ³μμ κ°μ λ³κ²½ν μλ μλ€.
function foo() {
const x = 1;
const y = 2;
const z = 10;
// μΌλ°μ μΌλ‘ ν΄λ‘μ λΌκ³ νμ§ μλλ€.
function bar() {
const z = 3;
debugger;
// μμ μ€μ½νμ μλ³μλ₯Ό μ°Έμ‘°νμ§ μλλ€.
console.log(z);
}
return bar;
}
const bar = foo();
bar();
μλ°μ€ν¬λ¦½νΈμ λͺ¨λ ν¨μλ μμ μ€μ½νλ₯Ό κΈ°μ΅νλ―λ‘ μ΄λ‘ μ μΌλ‘ λͺ¨λ ν¨μλ ν΄λ‘μ μ΄μ§λ§ μΌλ°μ μΌλ‘ λͺ¨λ ν¨μλ₯Ό ν΄λ‘μ λΌκ³ νμ§λ μλλ€. μμ μ½λμμ μ€μ²©ν¨μ bar()λ μΈλΆν¨μ foo() λ³΄λ€ λ μ€λ μ μ§λμ§λ§ μμ μ€μ½νμ μ΄λ ν μλ³μλ μ°Έμ‘°νμ§ μκΈ° λλ¬Έμ λΈλΌμ°μ λ μ΅μ νλ₯Ό ν΅ν΄ μμ μ€μ½νλ₯Ό κΈ°μ΅νμ§ μλλ€. λ°λΌμ bar() ν¨μλ ν΄λ‘μ λΌκ³ ν μ μλ€.
ν΄λ‘μ λ μ€μ²©ν¨μκ° μμ μ€μ½νμ μλ³μλ₯Ό μ°Έμ‘°νκ³ μκ³ μ€μ²© ν¨μκ° μΈλΆ ν¨μλ³΄λ€ λ μ€λ μ μ§λλ κ²½μ°μ νμ νλ κ²μ΄ μΌλ°μ μ΄λ€. ν΄λ‘μ μ μν΄ μ°Έμ‘°λλ μμ μ€μ½νμ λ³μλ₯Ό μμ λ³μλΌκ³ λΆλ₯Έλ€.
ν΄λ‘μλ μλ°μ€ν¬λ¦½νΈμ κ°λ ₯ν κΈ°λ₯μΌλ‘, νμνλ€λ©΄ μ κ·Ήμ μΌλ‘ νμ©ν΄μΌ νλ€. ν΄λ‘μ κ° μ μ©νκ² μ¬μ©λλ μν©μ μ΄ν΄λ³΄μ.
ν΄λ‘μ λ μν(state)λ₯Ό μμ νκ² λ³κ²½νκ³ μ μ§νκΈ° μν΄ μ¬μ©νλ€. λ€μ λ§ν΄, μνκ° μλμΉ μκ² λ³κ²½λμ§ μλλ‘ μνλ₯Ό μμ νκ² μλ(information hiding) νκ³ νΉμ ν¨μμκ²λ§ μν λ³κ²½μ νμ©νκΈ° μν΄ μ¬μ©νλ€.
// μΉ΄μ΄νΈ μν λ³μ
let num = 0;
// μΉ΄μ΄νΈ μν λ³κ²½ ν¨μ
const increase = function () {
// μΉ΄μ΄νΈ μνλ₯Ό 1λ§νΌ μ¦κ° μν¨λ€.
return ++num;
};
console.log(increase()); // 1
console.log(increase()); // 2
console.log(increase()); // 3
μμ μ½λλ λ€μκ³Ό κ°μ μ΄μ λ‘ μ€λ₯λ₯Ό λ°μμν¬ κ°λ₯μ±μ λ΄ν¬νκ³ μλ μ’μ§ μμ μ½λμ΄λ€.
νμ§λ§ μΉ΄μ΄νΈ μνλ μ μ λ³μλ₯Ό ν΅ν΄ κ΄λ¦¬ λκ³ μκΈ° λλ¬Έμ μλμΉ μκ² μνκ° λ³κ²½λ μ μλ€. λ°λΌμ increase ν¨μλ§μ΄ num λ³μλ₯Ό μ°Έμ‘°νκ³ λ³κ²½ν μ μλλ‘ μ μλ³μ numμ increase ν¨μμ μ§μλ³μλ‘ λ°κΎΈκ³ ν΄λ‘μ λ₯Ό μ¬μ©ν΄ μ£Όλκ²μ΄ λ°λμ§νλ€.
// μΉ΄μ΄νΈ μν λ³κ²½ ν¨μ
const increase = (function () {
// μΉ΄μ΄νΈ μν λ³μ
let num = 0;
// ν΄λ‘μ
return function () {
// μΉ΄μ΄νΈ μνλ₯Ό 1λ§νΌ μ¦κ° μν¨λ€.
return ++num;
};
}());
console.log(increase()); // 1
console.log(increase()); // 2
console.log(increase()); // 3
λ€μμ ν¨μν νλ‘κ·Έλλ°μμ ν΄λ‘μ λ₯Ό νμ©νλ κ°λ¨ν μμ λ€.
// ν¨μλ₯Ό μΈμλ‘ μ λ¬λ°κ³ ν¨μλ₯Ό λ°ννλ κ³ μ°¨ ν¨μ
// μ΄ ν¨μλ μΉ΄μ΄νΈ μνλ₯Ό μ μ§νκΈ° μν μμ λ³μ counterλ₯Ό κΈ°μ΅νλ ν΄λ‘μ λ₯Ό λ°ννλ€.
function makeCounter(aux) {
// μΉ΄μ΄νΈ μνλ₯Ό μ μ§νκΈ° μν μμ λ³μ
let counter = 0;
// ν΄λ‘μ λ₯Ό λ°ν
return function () {
// μΈμλ‘ μ λ¬ λ°μ 보쑰 ν¨μμ μν λ³κ²½μ μμνλ€.
counter = aux(counter);
return counter;
};
}
// 보쑰 ν¨μ
function increase(n) {
return ++n;
}
// 보쑰 ν¨μ
function decrease(n) {
return --n;
}
// ν¨μλ‘ ν¨μλ₯Ό μμ±νλ€.
// makeCounter ν¨μλ 보쑰 ν¨μλ₯Ό μΈμλ‘ μ λ¬λ°μ ν¨μλ₯Ό λ°ννλ€
const increaser = makeCounter(increase); // β
console.log(increaser()); // 1
console.log(increaser()); // 2
// increaser ν¨μμλ λ³κ°μ λ
립λ λ μ컬 νκ²½μ κ°κΈ° λλ¬Έμ μΉ΄μ΄ν° μνκ° μ°λνμ§ μλλ€.
const decreaser = makeCounter(decrease); // β‘
console.log(decreaser()); // -1
console.log(decreaser()); // -2
makerCounter ν¨μλ₯Ό νΈμΆν΄ ν¨μλ₯Ό λ°νν λ λ°νλ ν¨μλ μμ λ§μ λ 립λ λ μ컬 νκ²½μ κ°κΈ° λλ¬Έμ λ€μκ³Ό κ°μ΄ μ½λλ₯Ό μμ ν΄μ£Όμ΄μΌ νλ€.
// ν¨μλ₯Ό λ°ννλ κ³ μ°¨ ν¨μ
// μ΄ ν¨μλ μΉ΄μ΄νΈ μνλ₯Ό μ μ§νκΈ° μν μμ λ³μ counterλ₯Ό κΈ°μ΅νλ ν΄λ‘μ λ₯Ό λ°ννλ€.
const counter = (function () {
// μΉ΄μ΄νΈ μνλ₯Ό μ μ§νκΈ° μν μμ λ³μ
let counter = 0;
// ν¨μλ₯Ό μΈμλ‘ μ λ¬λ°λ ν΄λ‘μ λ₯Ό λ°ν
return function (aux) {
// μΈμλ‘ μ λ¬ λ°μ 보쑰 ν¨μμ μν λ³κ²½μ μμνλ€.
counter = aux(counter);
return counter;
};
}());
// 보쑰 ν¨μ
function increase(n) {
return ++n;
}
// 보쑰 ν¨μ
function decrease(n) {
return --n;
}
// 보쑰 ν¨μλ₯Ό μ λ¬νμ¬ νΈμΆ
console.log(counter(increase)); // 1
console.log(counter(increase)); // 2
// μμ λ³μλ₯Ό 곡μ νλ€.
console.log(counter(decrease)); // 1
console.log(counter(decrease)); // 0
μΊ‘μνλ κ°μ²΄μ μνλ₯Ό λνλ΄λ νλ‘νΌν°μ νλ‘νΌν°λ₯Ό μ°Έμ‘°νκ³ μ‘°μν μ μλ λμμΈ λ©μλλ₯Ό νλλ‘ λ¬Άλκ²μ λ§νλ€.
μλ°μ€ν¬λ¦½νΈλ μ 보 μλμ μμ νκ² μ§μνμ§ μλλ€. μΈμ€ν΄μ€ λ©μλλ₯Ό μ¬μ©νλ€λ©΄ μμ λ³μλ₯Ό ν΅ν΄ privateμ νλ΄ λΌ μλ μμ§λ§ νλ‘ν νμ
λ©μλλ₯Ό μ¬μ©νλ©΄ μ΄λ§μ λ λΆκ°λ₯ν΄μ§λ€
var funcs = [];
for (var i = 0; i < 3; i++) {
funcs[i] = function () { return i; }; // β
}
for (var j = 0; j < funcs.length; j++) {
console.log(funcs[j]()); // β‘
}
μ for λ¬Έμ μ½λλΈλ‘ λ΄μμ var ν€μλλ‘ μ μΈν λ³μ i λ λΈλ‘ λ 벨 μ€μ½νκ° μλ ν¨μ λ 벨 μ€μ½νλ₯Ό κ°κΈ° λλ¬Έμ μ μλ³μμ΄λ€. λ°λΌμ λ°°μ΄μ μμλ‘ μΆκ°ν ν¨μλ₯Ό νΈμΆνλ©΄ μ μ λ³μ iλ₯Ό μ°Έμ‘°νμ¬ iμ κ° 3μ μΆλ ₯νλ€.
var funcs = [];
for (var i = 0; i < 3; i++){
funcs[i] = (function (id) { // β
return function () {
return id;
};
}(i));
}
for (var j = 0; j < funcs.length; j++) {
console.log(funcs[j]());
}
μ μμ λ μλ°μ€ν¬λ¦½νΈμ ν¨μ λ 벨 μ€μ½ν νΉμ±μΌλ‘ μΈν΄ for λ¬Έμ λ³μ μ μΈλ¬Έμμ var ν€μλλ‘ μ μΈν λ³μκ° μ μ λ³μκ° λκΈ° λλ¬Έμ λ°μνλ νμμ΄λ€. ES6μ let ν€μλλ₯Ό μ¬μ©νλ©΄ μ΄ κ°μ λ²κ±°λ‘μμ΄ κΉλνκ² ν΄κ²°λλ€.
const funcs = [];
for (let i = 0; i < 3; i++) {
funcs[i] = function () { return i; };
}
for (let i = 0; i < funcs.length; i++) {
console.log(funcs[i]()); // 0 1 2
}
constλ let ν€μλλ₯Ό μ¬μ©νλ λ°λ³΅λ¬Έ(forλ¬Έ, for ... in λ¬Έ, for ... of λ¬Έ, while λ¬Έ λ±)μ μ½λ λΈλ‘μ λ°λ³΅ μ€νν λλ§λ€ μλ‘μ΄ λ μ컬 νκ²½μ μμ±νμ¬ λ°λ³΅ν λΉμμ λ§μ§λ§ μνλ₯Ό λ§μΉ μ€λ μμ μ°λ κ² μ²λΌ μ μ₯νλ€.