์ด๋ฒ ํฌ์คํ ์ ์๋ฐ์คํฌ๋ฆฝํธ ํด๋ก์ ์ ๋ํด์ ์ ๋ฆฌํด๋ณด์.
ํด๋ก์ ๋ ์๋ฐ์คํฌ๋ฆฝํธ ๋ฟ๋ง ์๋๋ผ ํจ์๋ฅผ ์ผ๊ธ๊ฐ์ฒด๋ก ์ทจ๊ธํ๋ ํจ์ํ ํ๋ก๊ทธ๋๋ฐ ์ธ์ด์์ ๋ง์ด ์ฐ์ด๋ ํน์ฑ์ด๋ค.
๋ฐ๋ผ์ EcmaScript ์ฌ์์๋ ๋ฑ์ฅํ์ง ์์ผ๋ฉฐ MDN์์๋ ๋ค์๊ณผ ๊ฐ์ด ์ค๋ช ์ด ๋์ด์๋ค.
A Closure is the combination of a function and the lexical environment within which that function was declared
ํด๋ก์ ๋ ํจ์๊ฐ ์ ์ธ๋ ๋ ์์ปฌ ํ๊ฒฝ์ ์ฐ๊ด๋์๋ค๊ณ ์ ํ์๋๋ฐ, ์ผ๋จ ๋ ์์ปฌ ํ๊ฒฝ์ด ๋ฌด์์ธ์ง ์ดํด๋ณด์!
๋ ์์ปฌ ์ค์ฝํ๋ ํจ์์ ์์ ์ค์ฝํ๋ฅผ ํจ์๋ฅผ ์ด๋์ ํธ์ถํ๋์ง๋ณด๋ค ์ด๋์ ์ ์ธ์ ํ๋์ง์ ๋ฐ๋ผ ๊ฒฐ์ ํ๋ ๊ฒ์ด๋ค.
๋ค์ ์ฝ๋๋ฅผ ๋ณด๊ณ ์คํ๊ฒฐ๊ณผ๋ฅผ ์์ธกํด๋ณด์. ๐
const x = 1;
function outerFunc() {
const x = 10;
innerFunc()
}
function innerFunc() {
console.log(x)
}
outerFunc()
๋ง์ฝ ์กฐ๊ธ ํท๊ฐ๋ฆฐ๋ค๋ฉด, ์์ง ๋ ์์ปฌ ์ค์ฝํ์ ๋ํด ์ ๋๋ก ์ดํดํ์ง ๋ชปํ๊ฒ์ด๋ค! ์กฐ๊ธ์ด๋ผ๋ ํท๊ฐ๋ฆฐ๋ค๋ฉด ์คํ ์ปจํ ์คํธ ํฌ์คํ ์ ์ฐธ์กฐํ๋ ๊ฒ์ ์ถ์ฒํ๋ค.
innerFunc๊ฐ ์ ์ธ๋ ๊ณณ์ outerFunc ๋ด๋ถ๊ฐ ์๋๋ผ ์ธ๋ถ์ด๊ธฐ ๋๋ฌธ์, outerFunc์์ ๋ง๋ ๋ณ์ x๋ outerFunc์์๋ ๋ณด์ด์ง ์๋๋ค. ๋ฐ๋ผ์ ์ ์ญ ์ค์ฝํ์ ์๋ x๋ฅผ ์ฐธ์กฐํ๊ฒ ๋๋ฉฐ, ์ถ๋ ฅ ๊ฒฐ๊ณผ๋ 1์ด ๋์จ๋ค.
๊ทธ๋ฌ๋ฉด ํด๋ก์ ์ ๋ ์์ปฌ ํ๊ฒฝ์ ์ด๋ค ๊ด๊ณ๊ฐ ์์๊น?
const x = 1
function outer() {
const x = 10;
const inner = function() {console.log(x)}
return inner
}
const innerFunc = outer();
innerFunc()
์ ์ฝ๋๋ฅผ ์ดํด๋ณด๋ฉด innerfunc์๋ outerํจ์ ๋ด์์ ์์ฑ๋ inner ํจ์๊ฐ return๋๋ค. ๊ทธ๋ฆฌ๊ณ outer ํจ์ ์์ฒด๋ stack์์ ์ ๊ฑฐ๋์ง๋ง, inner ํจ์๋ ๊ณ์ํด์ outer ํจ์์ ๋ณ์์ธ x๋ฅผ ์ฌ์ฉํ ์ ์๋ค.
์์์ ์๋ฐ์คํฌ๋ฆฝํธ๋ ๋ ์์ปฌ ์ค์ฝํ๋ฅผ ๋ฐ๋ฅธ๋ค๊ณ ์ด์ผ๊ธฐํ๋ค. ๋ฐ๋ผ์ ํจ์๋ ์ฒ์ ์์ฑ๋ ๋ ์ ์ธ๋ ๊ณณ์ ์์ ์ปจํ ์คํธ๋ฅผ ๊ธฐ์ตํ๊ฒ ๋๋ค.
์์ ์์๋ฅผ ๋ณด๋ฉด inner ํจ์๋ outer ํจ์ ์์ ์ ์ธ์ด ๋์๊ธฐ ๋๋ฌธ์, ์์ฑ๋ ๋์ ์์ ์ค์ฝํ์ธ outer ํจ์๋ฅผ ๊ธฐ์ตํ๋ค.
๋ฐ๋ผ์ outer๊ฐ ์คํ์ด ์๋ฃ๋์ด ์คํ์์ ์ ๊ฑฐ๋ ํ์๋ ๋ณ์ x์ ๊ฐ์ ์ธ์ ๋ ์ฐธ์กฐํ์ฌ ๊ฐ์ ธ์ฌ ์ ์๋ค.
์ด๋ฌํ ๊ฐ๋ ์ ํด๋ก์ ๋ผ๊ณ ํ๋ค.
๊ทธ๋ ๋ค๋ฉด ํด๋ก์ ๋ ์ด๋์ ํ์ฉ๋ ์ ์์๊น? ํด๋ก์ ๋ ์ํ๋ฅผ ์์ ํ๊ฒ ๋ณ๊ฒฝํ๊ณ ์ ์ง์ํค๊ธฐ ์ํด ์ฌ์ฉ๋๋ค.
๋ค์ ์ฝ๋๋ฅผ ๋ณด์.
let num = 0;
const add = function() {
return ++num;
}
console.log(add())
console.log(add())
console.log(add())
num์ 1์ฉ ์ฆ๊ฐ์ํค๋ ์ฝ๋์ด๋ค. ์ด ์ฝ๋๋ ๊ทธ๋ญ์ ๋ญ ์ ๋์ ํ์ง๋ง ์ฌ์ค ์ฌ๋ฌ๊ฐ์ง ๋ฌธ์ ๋ฅผ ๋ฐ์์ํฌ ์ ์๋ค.
์ ์ญ์ num ๋ณ์๊ฐ ์ ์ธ๋์ด์์ด์ ๋ค๋ฅธ ํจ์์์ ํด๋น ๊ฐ์ ๋ณ๊ฒฝ์ํค๋ ๊ฒฝ์ฐ state์ด ๋ฐ๋์ด ๋ฌธ์ ๋ฅผ ์ผ์ผํฌ ์ ์๊ธฐ ๋๋ฌธ์ด๋ค.
์ด๋ฐ ๋ฌธ์ ์ ์ ํด๊ฒฐํ๊ธฐ ์ํด ํด๋ก์ ๋ฅผ ํ์ฉํ ์ ์๋ค.
const add = (function() {
let num = 0;
//ํด๋ก์ ํ์ฉ
return function() {
// num ์ 1 ๋งํผ ์ฆ๊ฐ์ํจ๋ค
return ++num;
}
}())
console.log(add())
console.log(add())
console.log(add())
์ด๋ ๊ฒ add๋ผ๋ ํจ์ ์์ num ๋ณ์๋ฅผ ์
๋ ฅํด์ฃผ๊ณ , ํด๋น ํจ์๊ฐ ์์ ํจ์ add
์์์ ์ ์ธ์ด ๋๊ฒ ํจ์ผ๋ก์จ ํด๋น ํจ์๊ฐ num ๊ฐ์ ์ํ๋ฅผ ์ ์งํ๊ฒ ํ์ฌ ํ์ฉ์ ํ ์ ์๋ค.
๊ทธ๋ผ ๋ํ๊ธฐ์ ์ด์ด์ ๋นผ๊ธฐ ๊ธฐ๋ฅ๋ ๊ตฌํํด๋ณด์.
const counter = (function () {
let num = 0;
return {
add() {
return ++num;
},
subtract() {
return num > 0 ? --num : 0;
},
};
})();
console.log(counter.subtract());
console.log(counter.add());
console.log(counter.add());
console.log(counter.add());
console.log(counter.add());
console.log(counter.subtract());
counter์๋ ์ฆ์ ์คํํจ์๊ฐ ์์ฑํ add์ subtract๋ฅผ ๋ฉ์๋๋ฅผ ๊ฐ์ง ๊ฐ์ฒด๊ฐ return๋๋ค. ์ฌ๊ธฐ์ ์ค์ํ ์ ์ num ๋ณ์๋ add์ subtract๋ง์ด ์ ๊ทผํ ์ ์๋ค๋ ๊ฒ์ด๋ค.
๋ณ์๊ฐ์ ์ธ์ ๋ ๋ณ๊ฒฝ๋ ์ ์๊ธฐ ๋๋ฌธ์ ํ๋ก๊ทธ๋จ์ ์์ ์ฑ์ ๋์ด๊ธฐ ์ํด์๋ ํด๋ก์ ๋ฅผ ์ ๊ทน์ ์ผ๋ก ์ฌ์ฉํด์ผ ํ๋ค.
๋ง์ง๋ง์ผ๋ก ํจ์ํ ํ๋ก๊ทธ๋๋ฐ์์ ํด๋ก์ ๋ฅผ ํ์ฉํ๋ ์์ ๋ฅผ ๋ณด๋ฉฐ ๋ง์น๋๋ก ํ์.
// ์นด์ดํธ ์ํ๋ฅผ ์ ์งํ๊ธฐ ์ํ ๋ณ์๋ฅผ ๊ธฐ์ตํ๋ ํด๋ก์ ๋ฅผ ๋ฐํ
const counter = (function () {
// ์นด์ดํธ ์ํ๋ฅผ ์ ์งํ๊ธฐ ์ํ ๋ณ์
let count = 0;
// ํจ์๋ฅผ ์ธ์๋ก ์ ๋ฌ๋ฐ๋ higher order function์ ํด๋ก์ ๋ก ๋ฐํ
return function (arithmetics) {
// ํ์ฌ ์นด์ดํธ ๊ฐ์ ํด๋ก์ ธ๊ฐ ์ ๋ฌ๋ฐ์ ํจ์๋ฅผ ์คํ์ํค๋ ํจ์ ๋ฐํ
count = arithmetics(count);
return count;
};
})();
function add(n) {
return ++n;
}
function subtract(n) {
return --n;
}
console.log(counter(add));
console.log(counter(add));
console.log(counter(add));
console.log(counter(subtract));
console.log(counter(subtract));
console.log(counter(add));
์ด๋ฒ ํฌ์คํ ์์๋ ํด๋ก์ ์ ๋ํด ์์๋ณด์๋ค.
๋ฆฌ์กํธ ๊ณต์ ๋ฌธ์๋ฅผ ์ดํด๋ณผ๋ ์ฒ์ ํ์ด๋จธ ์์์ฝ๋์์ ํด๋ก์ ๋ฅผ ํ์ฉํด์ ์์ฑ๋ ์ฝ๋๊ฐ ์ดํด๊ฐ ์๋์๋๋ฐ, ํด๋ก์ ๋ฅผ ๊ณต๋ถํ๊ณ ๋ค์ ์ฝ์ด๋ณด๋ ์ดํด๊ฐ ๋์ด์ ๋ฟ๋ฏํ๋ค.๐๐