๋ชจ๋ ์๋ฐ์คํฌ๋ฆฝํธ Deep Dive ๋์์ 24์ฅ์ ์ ๋ฆฌํ์์ต๋๋ค.
ํด๋ก์
MDN์์
A closure is the combination of a function and the lexical environment within which that function was declared.
ํด๋ก์ ๋ ํจ์์ ๊ทธ ํจ์๊ฐ ์ ์ธ๋ ๋ ์์ปฌ ํ๊ฒฝ๊ณผ์ ์กฐํฉ์ด๋ค.
// 24-03
const x = 1;
function foo() {
const x = 10;
// ์์ ์ค์ฝํ๋ ํจ์ ์ ์ ํ๊ฒฝ(์์น)์ ๋ฐ๋ผ ๊ฒฐ์ ๋๋ค.
// ํจ์ ํธ์ถ ์์น์ ์์ ์ค์ฝํ๋ ์๋ฌด๋ฐ ๊ด๊ณ๊ฐ ์๋ค.
bar();
}
// ํจ์ bar๋ ์์ ์ ์์ ์ค์ฝํ, ์ฆ ์ ์ญ ๋ ์์ปฌ ํ๊ฒฝ์ [[Environment]]์ ์ ์ฅํ์ฌ ๊ธฐ์ตํ๋ค.
function bar() {
console.log(x);
}
foo(); // 1
bar(); // 1
foo ํจ์์ bar ํจ์๋ ๋ชจ๋ ์ ์ญ์์ ์ ์๋ ์ ์ญ ํจ์์ด๋ค. ํจ์์ ์์ ์ค์ฝํ๋ ํจ์๋ฅผ ์ด๋์ ์ ์ํ๋๋์ ๋ฐ๋ผ ๊ฒฐ์ ๋๋ฏ๋ก foo ํจ์์ bar ํจ์์ ์์ ์ค์ฝํ๋ ์ ์ญ์ด๋ค.
๋ ์์ปฌ ํ๊ฒฝ์ "์ธ๋ถ ๋ ์์ปฌ ํ๊ฒฝ์ ๋ํ ์ฐธ์กฐ"์ ์ ์ฅํ ์ฐธ์กฐ๊ฐ, ์ฆ ์์ ์ค์ฝํ์ ๋ํ ์ฐธ์กฐ๋ ํจ์ ์ ์๊ฐ ํ๊ฐ๋๋ ์์ ์ ํจ์๊ฐ ์ ์๋ ํ๊ฒฝ(์์น)์ ์ํด ๊ฒฐ์ ๋๋ค. ์ด๊ฒ์ด ๋ฐ๋ก ๋ ์์ปฌ ์ค์ฝํ๋ค.
๋ ์์ปฌ ์ค์ฝํ๊ฐ ๊ฐ๋ฅํ๋ ค๋ฉด ํจ์๋ ์์ ์ด ํธ์ถ๋๋ ํ๊ฒฝ๊ณผ๋ ์๊ด์์ด ์์ ์ด ์ ์๋ ํ๊ฒฝ, ์ฆ ์์ ์ค์ฝํ๋ฅผ ๊ธฐ์ตํด์ผ ํ๋ค. ํจ์๋ ์์ ์ ๋ด๋ถ ์ฌ๋กฏ [[Environment]]์ ์์ ์ด ์ ์๋ ํ๊ฒฝ, ์ฆ ์์ ์ค์ฝํ์ ์ฐธ์กฐ๋ฅผ ์ ์ฅํ๋ค.
์๋ ์์์ฒ๋ผ ์ธ๋ถ ํจ์๋ณด๋ค ์ค์ฒฉ ํจ์๊ฐ ๋ ์ค๋ ์ ์ง๋๋ ๊ฒฝ์ฐ ์ค์ฒฉ ํจ์๋ ์ด๋ฏธ ์๋ช ์ฃผ๊ธฐ๊ฐ ์ข ๋ฃํ ์ธ๋ถ ํจ์์ ๋ณ์๋ฅผ ์ฐธ์กฐํ ์ ์๋ค. ์ด๋ฌํ ์ค์ฒฉ ํจ์๋ฅผ ํด๋ก์ ๋ผ๊ณ ๋ถ๋ฅธ๋ค.
//24-05
const x = 1;
function outer() {
const x = 10;
const inner = function () {
console.log(x);
}
return inner;
}
const innerFunc = outer();
innerFunc(); // 10
๋๋ถ๋ถ์ ๋ชจ๋ ๋ธ๋ผ์ฐ์ ๋ ์ต์ ํ๋ฅผ ํตํด ์์ ์ค์ฝํ์ ์๋ณ์ ์ค์์ ํด๋ก์ ๊ฐ ์ฐธ์กฐํ๊ณ ์๋ ์๋ณ์๋ง์ ๊ธฐ์ตํ๋ค. ํด๋ก์ ์ ์ํด ์ฐธ์กฐ๋๋ ์์ ์ค์ฝํ์ ๋ณ์๋ฅผ ์์ ๋ณ์๋ผ๊ณ ๋ถ๋ฅธ๋ค.
ํด๋ก์ ๋ ์ํ๋ฅผ ์์ ํ๊ฒ ๋ณ๊ฒฝํ๊ณ ์ ์งํ๊ธฐ ์ํด ์ฌ์ฉํ๋ค. ์ฆ ์ํ๋ฅผ ์์ ํ๊ฒ ์๋ํ๊ณ ํน์ ํจ์์๊ฒ๋ง ์ํ ๋ณ๊ฒฝ์ ํ์ฉํ๊ธฐ ์ํด ์ฌ์ฉํ๋ค.
// 24-11
const increase = (function (){
let num = 0;
return function () {
return ++num;
}
}());
console.log(increase()); // 1
console.log(increase()); // 2
console.log(increase()); // 3
์ฆ์ ์คํ ํจ์๋ ํธ์ถ๋ ์ดํ ์๋ฉธํ์ง๋ง ์ฆ์ ์คํ ํจ์๊ฐ ๋ฐํํ ํด๋ก์ ๋ increase ๋ณ์์ ํ ๋น๋์ด ํธ์ถํ๋ค. ๋ํ ํ ๋ฒ๋ง ์คํ๋๋ฏ๋ก increase๊ฐ ํธ์ถ๋ ๋๋ง๋ค num ๋ณ์๊ฐ ์ฌ์ฐจ ์ด๊ธฐํ๋ ์ผ์ ์์ ๊ฒ์ด๋ค.
// 24-14
// ํจ์๋ฅผ ์ธ์๋ก ์ ๋ฌ๋ฐ๊ณ ํจ์๋ฅผ ๋ฐํํ๋ ๊ณ ์ฐจํจ์
function makeCounter(aux) {
let counter = 0;
return function () {
counter = aux(counter);
return counter;
}
}
function increase(n) {
return ++n;
}
function decrease(n) {
return --n;
}
const increaser = makeCounter(increase);
const decreaser = makeCounter(decrease);
console.log(increaser()); // 1
console.log(decreaser()); // -1
์ ์์ ๋ increaser๊ณผ decreaser์ ๋ณ๊ฐ์ ๋ ๋ฆฝ๋ ๋ ์์ปฌ ํ๊ฒฝ์ ๊ฐ๊ธฐ ๋๋ฌธ์ ์นด์ดํฐ ์ํ๊ฐ ์ฐ๋ํ์ง ์๋๋ค.
๋ ๋ฆฝ๋ ์นด์ดํฐ๊ฐ ์๋๋ผ ์ฐ๋ํ์ฌ ์ฆ๊ฐ์ด ๊ฐ๋ฅํ ์นด์ดํฐ๋ฅผ ๋ง๋ค๋ ค๋ฉด ๋ ์์ปฌ ํ๊ฒฝ์ ๊ณต์ ํ๋ ํด๋ก์ ๋ฅผ ๋ง๋ค์ด์ผ ํ๋ค.
// 24-15
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(decrease)); // 0
์บก์ํ๋ ๊ฐ์ฒด์ ์ํ๋ฅผ ๋ํ๋ด๋ ํ๋กํผํฐ๋ ํ๋กํผํฐ๋ฅผ ์ฐธ์กฐํ๊ณ ์๋ ๋์์ธ ๋ฉ์๋๋ฅผ ํ๋๋ก ๋ฌถ๋ ๊ฒ์ ๋งํ๋ค. ์ ๋ณด ์๋์ ๊ฒฐํฉ๋๋ฅผ ๋ฎ์ถ๋ ํจ๊ณผ๊ฐ ์๋ค.
์๋ฐ์คํฌ๋ฆฝํธ๋ ์ ๋ณด ์๋์ ์์ ํ๊ฒ ์ง์ํ์ง๋ ์๋๋ค. ์ง๊ธ์ ํด๋์ค์ private ํ๋๋ฅผ ์ ์ํ ์ ์๋ ์๋ก์ด ํ์ค ์ฌํฅ์ด ์ ์ ๋์ด ์๋ค.
// 24-20
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]()); // 3, 3, 3
}
์ ์์ ๋ฅผ ํด๋ก์ ๋ฅผ ์ฌ์ฉํด์ ๋ง๋ค๋ฉด
// 24-21
var funcs = [];
for(var i = 0; i < 3; i++){
funcs[i] = (function (id) { // ์ง์ญ ๋ณ์ i์ ํ์ฌ ํ ๋น๋์ด ์๋ ๊ฐ์ ์ธ์๋ก ์ ๋ฌ๋ฐ์ ๋งค๊ฐ๋ณ์ id์ ํ ๋นํ ํ ์ค์ฒฉ ํจ์๋ฅผ ๋ฐํํ๊ณ ์ข
๋ฃํ๋ค.
return function () {
return id;
}
}(i));
}
for(var j = 0; j < func.length; j++) {
console.log(funcs[j]());
}
Ref
- ์ด์ ๋ชจ ์ , โ๋ชจ๋ ์๋ฐ์คํฌ๋ฆฝํธ Deep Diveโ, ์ํค๋ถ์ค