# ํด๋ก์ ธ(Closure)
ํด๋ก์ ธ๋ ํจ์์ ์คํ์ด ๋๋ ๋ค์๋ ํจ์์ ์ ์ธ๋ ๋ณ์์ ๊ฐ์ ์ ๊ทผํ ์ ์๋ ์๋ฐ์คํฌ๋ฆฝํธ์ ์ฑ์ง์ ๋๋ค. ์๋ฐ์คํฌ๋ฆฝํธ๋ฅผ ๋ค๋ฅธ ์ธ์ด์ ๋น๊ตํ์ ๋ ์ฐจ๋ณํ๋๋ ์ ์ผํ ํน์ง์ธ๋ฐ์. ์ฝ๋๋ก ๋ฐ๋ก ์ดํด๋ณด๊ฒ ์ต๋๋ค.
function addCounter() {
var counter = 0;
return function() {
return counter++;
};
}
์ ์ฝ๋๋ addCounter()
๋ผ๋ ํจ์๋ฅผ ํ๋ ์์ฑํ๊ณ counter
๋ณ์๋ฅผ ํ๋ ์ ์ธํ ์ฝ๋์
๋๋ค. ์ ์ฑํฐ์์ ๋ฐฐ์ด ์ ํจ ๋ฒ์(์ค์ฝํ)๋ฅผ ์๊ธฐ์์ผ๋ณด๋ฉด counter
๋ผ๋ ๋ณ์๋ ํ์ฌ ํจ์ ์์ ์ ์ธ๋์ด ์๊ธฐ ๋๋ฌธ์ ํจ์ ์์์๋ง ์ ํจํ ์ ํจ ๋ฒ์๋ฅผ ๊ฐ๊ฒ ๋ฉ๋๋ค. ์๋์ ๊ฐ์ด ๋ง์ด์ฃ .
function addCounter() {
var counter = 0;
}
addCounter();
console.log(counter); // Uncaught ReferenceError: counter is not defined
ํจ์ ๋ฐ์์ counter
๋ณ์๋ฅผ ์ฐธ์กฐํ๋ ค๊ณ ํ๋ฉด ์ค๋ฅ๊ฐ ๋ฐ์๋ฉ๋๋ค. ๊ทธ ์ด์ ๋ ํจ์ ๋ฐ์์ counter
๋ผ๋ ๋ณ์๊ฐ ์ ์ธ๋ ์ ์ด ์๊ธฐ ๋๋ฌธ์
๋๋ค. ์ ๊ทธ๋ผ ์ด ๊ด์ ์์ ๋ค์ ํด๋ก์ ธ ์ฝ๋๋ก ๋์๊ฐ๋ณด๊ฒ ์ต๋๋ค.
function addCounter() {
var counter = 0;
return function() {
return counter++;
};
}
counter
๋ณ์ ๋ค์์ผ๋ก ์ฃผ๋ชฉํ ๋ถ๋ถ์ ํจ์๋ฅผ ๋ฐํํ๋ ๋ถ๋ถ(์ฝ๋ ๊ฐ์กฐ๋ ๋ถ๋ถ)์
๋๋ค. ์ฌ๊ธฐ์ ์ด๋ ๊ฒ ํจ์๋ฅผ ๋ฐํํ ์ ์๋ ์ด์ ๋ 'ํจ์๋ฅผ ๋ณ์๋ ์ธ์๋ก ๋๊ธธ ์ ์๋ ์๋ฐ์คํฌ๋ฆฝํธ์ ์ฑ์ง(์ผ๊ธ ๊ฐ์ฒด)' ๋๋ฌธ์
๋๋ค.
์ ๊ทธ๋ผ ์ด์ ์๋์ ๊ฐ์ด addCounter()
ํจ์๋ฅผ ์คํํด๋ณด๊ฒ ์ต๋๋ค.
addCounter();
์์ ๊ฒฐ๊ณผ๋ ๋ฌด์์ผ๊น์? ์ฝ์์ ํ๋ฒ ์ฐ์ด๋ณด๊ฒ ์ต๋๋ค.
console.log(addCounter());
์ถ๋ ฅ๋ ๊ฒฐ๊ณผ๋ ์๋์ ๊ฐ์ต๋๋ค.
ฦ () {
return counter++;
}
์ฌ๊ธฐ์ ๊ฐธ์ฐ๋ฑ ํ์๋ ๋ถ๋ค์ ๋ค์ ํ๋ฒ addCounter()
ํจ์ ์ฝ๋๋ฅผ ์ดํด๋ณด์๊ธฐ ๋ฐ๋๋๋ค. ์ ์๋น์ด addCounter()
ํจ์์ ์ญํ ์ addCounter()
ํจ์๋ฅผ ์คํํ์ ๋ ํจ์๋ฅผ ๋ฐํํ๋ ๊ฒ ์ด์์ต๋๋ค.
๊ทธ๋ผ ์ด์ ๋ฐํ๋ ํจ์๋ฅผ ์ดํด๋ณด๋ฉด counter++
๋ผ๋ ์ฝ๋๊ฐ ๋ณด์ผ ๊ฒ๋๋ค. ๊ทธ๋ฆฌ๊ณ ๊ทธ ๋ณ์๋ฅผ ์๋์ ๊ฐ์ด ์ ๊ทผํ๋ฉด ๋น์ฐํ ๋ ์ค๋ฅ๊ฐ ๋ฉ๋๋ค.
function addCounter() {
var counter = 0;
return function() {
return counter++;
};
}
addCounter();
console.log(counter); // Uncaught ReferenceError: counter is not defined
์ฝ๋๋ฅผ ์ฐฌ์ฐฌํ ์ดํด๋ณด๋ฉด addCounter()
ํจ์์ ์คํ์ด ๋๋ ์์ ์์๋ counter
๋ผ๋ ๋ณ์๋ ๋์ด์ ์ ๊ทผํ ์ ์๋ ์ํ๊ฐ ๋ฉ๋๋ค. ํจ์ ์์ ์ ์ธํ ๋ณ์๋ ํจ์ ์์์๋ง ์ ํจ ๋ฒ์๋ฅผ ๊ฐ๊ฒ ๋๋ฌธ์ด์ฃ .
์ ๊ทธ๋ผ ์ด์ ์๋ ์ฝ๋๋ฅผ ์คํํด๋ณด๊ฒ ์ต๋๋ค.
function addCounter() {
var counter = 0;
return function() {
return counter++;
};
}
var add = addCounter();
add(); // 0
add(); // 1
add(); // 2
์์ ๊ฐ์ด ์ฝ๋๋ฅผ ์คํํ์ ๋ ๋์ํ๋ ์ด์ ๊ฐ ๋ฌด์์ผ๊น์? ๊ทธ๊ฑด ๋ฐ๋ก addCounter()
๋ผ๋ ํจ์๊ฐ ๋ฐํํ ํจ์๋ฅผ add
๋ผ๋ ๋ณ์์ ๋ด์๋จ๊ธฐ ๋๋ฌธ์ add
๋ณ์ ์์ฒด๊ฐ ํจ์์ฒ๋ผ ๋์ํ๋ ๊ฒ์
๋๋ค. ๊ธฐ์ ์ฉ์ด๋ก ์ ํํ ํํํ์๋ฉด "add ๋ณ์๊ฐ addCounter()๊ฐ ๋ฐํํ ํจ์๋ฅผ ์ฐธ์กฐํ๊ณ ์๋ค" ์
๋๋ค.
์ด์ฒ๋ผ ํจ์์ ์คํ์ด ๋๋๊ณ ๋์๋ ํจ์ ์์ ๋ณ์๋ฅผ ์ฐธ์กฐํ ์ ์๋๊ฒ ๋ฐ๋ก ํด๋ก์ ธ์ ๋๋ค. ์ด๋ฌํ ํจํด์ ์์ฉํ๋ฉด private ๋ณ์๋ฅผ ๋ง๋ค๊ฑฐ๋ ํจ์ํ ํ๋ก๊ทธ๋๋ฐ์ ํ ์ ์์ต๋๋ค.
# private ๋ณ์
์ผ๋ฐ์ ์ผ๋ก ํ๋ก๊ทธ๋๋ฐ์์ ์ธ๋ถ์์ ์ฌ์ฉํ์ง ์๊ฑฐ๋ ์ ๊ทผํ๋ฉด ์ ๋๋ ๋ณ์์ ํจ์๋ private
๋ก ์ ์ธํ์ฌ ์ฌ์ฉํฉ๋๋ค. ํด๋ก์ ธ๋ฅผ ํ์ฉํ์ฌ private
๋ณ์๋ฅผ ๊ตฌํํ๋ ๋ฐฉ๋ฒ์ ์์๋ณด๊ฒ ์ต๋๋ค.
var fund = (function() {
var money = 0;
return {
deposit: function(amount) {
money += amount;
},
withdraw: function(amount) {
money -= amount;
},
getMoney: function() {
return money;
}
}
}());
fund.deposit(100); // 100
fund.deposit(100); // 200
fund.getMoney(); // 200
fund.money = 100000; // private ๋ณ์๋ก ๋ณ๊ฒฝ๋์ง ์๋๋ค.
fund.getMoney(); // 200
์ ์ฝ๋์์ ํธ์ถ๋ ํจ์ ๋ด๋ถ์ money
๋ณ์๋ ํจ์ ๋ด์์ ์ ๊ณตํ deposit
, withdraw
, getMoney
๋ฅผ ์ฌ์ฉํ๋ ๊ฒ ์ธ์ ์ ๊ทผํ๋ ๋ฐฉ๋ฒ์ด ์์ต๋๋ค. ์ด๋ ๊ฒ ํด๋ก์ ธ๋ฅผ ํ์ฉํ๋ฉด ์ธ๋ถ์์ ๋ณ์์ ์ง์ ์ ๊ทผํ๋ ๊ฒ์ ์ ํํ๋ private ๋ณ์๋ฅผ ๊ตฌํํ ์ ์์ต๋๋ค.
TIP
๊ธฐ์กด์ ์๋ฐ์คํฌ๋ฆฝํธ์๋ private
๋ณ์๋ฅผ ์ ์ธํ๋ ๋ฌธ๋ฒ์ด ์์์ง๋ง, 2021๋
Class์์ private
ํ๋์ ๋ฉ์๋๋ฅผ ์ง์ํ๋ ์๋ก์ด ํ์ค์ด ์ถ๊ฐ๋์์ต๋๋ค. ์๋ MDN ๋ฌธ์๋ฅผ ์ฐธ๊ณ ํ์๊ธฐ ๋ฐ๋๋๋ค.
MDN Web Docs - Private class features (opens new window)
# ํจ์ํ ํ๋ก๊ทธ๋๋ฐ
ํจ์ํ ํ๋ก๊ทธ๋๋ฐ์ด๋ ํน์ ๊ธฐ๋ฅ์ ๊ตฌํํ๊ธฐ ์ํด์ ํจ์์ ๋ด๋ถ ๋ก์ง์ ๋ณ๊ฒฝํ์ง ์์ ์ํ๋ก ์ฌ๋ฌ ๊ฐ์ ํจ์๋ฅผ ์กฐํฉํ์ฌ ๊ฒฐ๊ณผ ๊ฐ์ ๋์ถํ๋ ํ๋ก๊ทธ๋๋ฐ ํจํด์ ์๋ฏธํฉ๋๋ค. ์ปค๋ง(currying)์ด ํจ์ํ ํ๋ก๊ทธ๋๋ฐ์ ๋ํ์ ์ธ ์์ ๋๋ค. ์ฝ๋๋ก ๋ณด๊ฒ ์ต๋๋ค.
function add(num1, num2) {
return num1 + num2;
}
function curry(fn, a) {
return function(b) {
return fn(a, b);
};
}
var add3 = curry(add, 3);
add3(4); // 7
์์ ๊ฐ์ด ํด๋ก์ ธ๋ฅผ ํ์ฉํ๋ฉด ํจ์๋ฅผ ์กฐํฉํ์ฌ ๊ธฐ๋ฅ์ ๊ตฌํํด๋๊ฐ ์ ์์ต๋๋ค.
โ Scope Const & Let โ