# ํด๋กœ์ ธ(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

์œ„์™€ ๊ฐ™์ด ํด๋กœ์ ธ๋ฅผ ํ™œ์šฉํ•˜๋ฉด ํ•จ์ˆ˜๋ฅผ ์กฐํ•ฉํ•˜์—ฌ ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•ด๋‚˜๊ฐˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.