Javascript 'Closure'

Javascript

What is Closure ? ๐Ÿ’ก

ํด๋กœ์ €๋Š” ํ•จ์ˆ˜์™€ ํ•จ์ˆ˜๊ฐ€ ์„ ์–ธ๋œ ์–ดํœ˜์  ํ™˜๊ฒฝ์˜ ์กฐํ•ฉ์ด๋‹ค. by MDN

์—ญ์‹œ MDN ๋ง์€ ํ•œ๋ฒˆ์— ์•Œ์•„๋“ฃ๊ธฐ ์–ด๋ ค์šฐ๋ฏ€๋กœ ํ’€์–ด์„œ ์ •๋ฆฌํ•ด๋ณด์ž! ๐Ÿ˜…

ํด๋กœ์ ธ๋Š” ๊ณผ์—ฐ ๋ฌด์—‡์ผ๊นŒ??

๋จผ์ € ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ Deepdive ์ฑ…์— ์žˆ๋Š” ์—์ œ๋กœ ๋ณด๊ฒ ๋‹ค.

const outer = () => {
  const out = "outer!"; // 1. outer ํ•จ์ˆ˜ ์•ˆ์— ์ง€์—ญ๋ณ€์ˆ˜ out ์„ ์–ธ

  const inner = () => {
    console.log(out); // 2. ๋ฐ”๊นฅ์˜ out์„ ์ฐธ์กฐํ•ด console.log ์ถœ๋ ฅ
  };

  return inner; // 3. ๋ฐ”๊นฅ์˜ out์„ ์ฐธ์กฐํ•ด console.log๋ฅผ ์ถœ๋ ฅํ•˜๋Š” ํ•จ์ˆ˜๋ฅผ ๋ฐ˜ํ™˜
};

const foo = outer(); // 4. outerํ•จ์ˆ˜ ํ˜ธ์ถœ -> ๋ณ€์ˆ˜ foo์— innerํ•จ์ˆ˜์˜ ์ฃผ์†Œ๊ฐ’์ด ์ €์žฅ๋จ

foo(); // 5. 'outer!'

์ด ์†Œ์Šค์ฝ”๋“œ๋“ค์€ ํด๋กœ์ ธ์˜ ํ™•์‹คํ•œ ์˜ˆ์‹œ์ด๋‹ค.

์ฆ‰ ํด๋กœ์ ธ๋Š” ์–ด๋–ค ํ•จ์ˆ˜(outer) ๋‚ด๋ถ€์— ์„ ์–ธ๋œ ํ•จ์ˆ˜(inner)๊ฐ€ ๋ฐ”๊นฅ ํ•จ์ˆ˜(outer)์˜ ์ง€์—ญ๋ณ€์ˆ˜(outerVariable)๋ฅผ ์ฐธ์กฐํ•˜๋Š” ๊ฒƒ์ด ํ•จ์ˆ˜(outer)๊ฐ€ ์ข…๋ฃŒ๋œ ์ดํ›„์—๋„ ๊ณ„์† ์œ ์ง€๋˜๋Š” ํ˜„์ƒ์„ ๋งํ•ฉ๋‹ˆ๋‹ค. outer ํ•จ์ˆ˜์˜ ๋ผ์ดํ”„์‚ฌ์ดํด์ด inner ํ•จ์ˆ˜๋ณด๋‹ค ์งง์„๋•Œ ์ด์•ผ๊ธฐ์ด๋‹ค.

โš ๏ธ ๋‹ค๋งŒ !! ์ „์—ญ์ปจํ…์ŠคํŠธ์—์„œ ์ฐธ์กฐ๋˜๋Š” outer ํ•จ์ˆ˜๋Š” ์ข…๋ฃŒ๋˜๋Š” ๊ฒƒ์ด ๋งž์œผ๋‚˜ ์‚ฌ๋ผ์ง€์ง€์•Š๊ณ  ์กด์žฌ๋Š” ํ•œ๋‹ค. ๋‹ค๋งŒ ๋ฉ”๋ชจ๋ฆฌ ์–ด๋”˜๊ฐ€์—์„œ ์กด์žฌํ• ๋ฟ ๊ฐ€๋น„์ง€์ปฌ๋ ‰ํ„ฐ์— ์˜ํ•ด์„œ ์™„์ „ํžˆ ์†Œ๋ฉธ๋˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋‹ค. ์ ์–ด๋„ inner ํ•จ์ˆ˜๊ฐ€ ์—†์–ด์งˆ ๋•Œ๊นŒ์ง€๋Š” outer ํ•จ์ˆ˜๊ฐ€ ์กด์žฌํ•˜๊ฒŒ๋œ๋‹ค.


Why Closure exist ? ๐Ÿšจ

Scope

function scopeA() {
  const a = "ํ˜ธ๋ž‘์ด";

  function scopeB() {
    const a = "์‚ฌ์ž";

    console.log(a);
  }
  scopeB(); // ์‚ฌ์ž
  console.log(a);
}

scopeA(); // ํ˜ธ๋ž‘์ด
console.log(a); // reference error

scopeA๋ฅผ ํ˜ธ์ถœ ํ–ˆ์„ ๋•Œ ์‚ฌ์ž๊ฐ€ ์•„๋‹Œ ํ˜ธ๋ž‘์ด๊ฐ€ ์ถœ๋ ฅ๋˜์—ˆ๋‹ค. ์ด๊ฒƒ์€ scopeB ํ•จ์ˆ˜์˜ ๋ณ€์ˆ˜ ์„ ์–ธ ๋ฐ ํ• ๋‹น ๊ณผ์ •์ด scopeA์˜ ๋™์ž‘์— ์˜ํ–ฅ์„ ์ฃผ์ง€ ์•Š์•˜๋‹ค๋Š” ๊ฒƒ์ด๋‹ค. ์ฆ‰, scopeA์™€ scopeB๊ฐ€ ๊ณ ์œ ํ•œ ์Šค์ฝ”ํ”„๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค๊ณ  ๋งํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋ชจ๋“  ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์–ธ์–ด๋Š” ์ฝ”๋“œ๋ฅผ ํ•œ ์ค„์”ฉ ์ฝ๋Š”๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์ด๋ฅผ ๊ณ„์‚ฐ(์•ž์œผ๋กœ๋Š” ํ‰๊ฐ€ํ•œ๋‹ค๊ณ  ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.)ํ•ด ๋ฉ”๋ชจ๋ฆฌ์— ๊ณ„์‚ฐ๋œ ๊ฐ’์„ ์ €์žฅ(const a = โ€˜ํ˜ธ๋ž‘์ดโ€™)ํ•˜๊ฑฐ๋‚˜, ํŠน์ •ํ•œ ๋™์ž‘์„(console.log(a))ํ•œ๋‹ค.

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋Š” ํ”„๋กœ๊ทธ๋žจ์„ ํ‰๊ฐ€ํ•˜๊ธฐ ์ „๊ณผ ํ•จ์ˆ˜๋ฅผ ํ‰๊ฐ€ํ•˜๊ธฐ ์ „์— ๋ณ€์ˆ˜ ์„ ์–ธ๊ณผ ํ•จ์ˆ˜ ์„ ์–ธ ์ •๋ณด๋ฅผ ๋ฏธ๋ฆฌ ํ•œ ๋ฒˆ ์ญ‰ ํ›‘์–ด์„œ ์ˆ˜์ง‘ํ•œ๋‹ค. (์‹คํ–‰์ปจํ…์ŠคํŠธ์˜ Environment Record๋ฅผ ์ˆ˜์ง‘ํ•˜๋Š” ๊ณผ์ •)

ํ”„๋กœ๊ทธ๋žจ์„ ์‹œ์ž‘ํ•˜๊ธฐ ์ „์— scopeAํ•จ์ˆ˜ ์„ ์–ธ ์ •๋ณด๋ฅผ ์ˆ˜์ง‘ํ•˜๊ณ  ํ•œ ์ค„์”ฉ ํ‰๊ฐ€๋ฅผ ํ•˜๋‹ค๊ฐ€, scopeA๊ฐ€ ํ˜ธ์ถœ๋˜๋Š” ์‹œ์ ์— scopeA ๋‚ด๋ถ€์˜ (๋ฌธ์ž์—ด ํ˜ธ๋ž‘์ด๊ฐ€ ํ• ๋‹น๋˜๋Š”) a ์™€ scopeB์˜ ์ •๋ณด๋ฅผ ์ˆ˜์ง‘ํ•˜๋Š” ๊ฒƒ์ด๋‹ค. ์ด๋ ‡๊ฒŒ ์ •๋ณด๋ฅผ ์ˆ˜์ง‘ํ•˜๊ณ  ๋‹ค์‹œ ์ฒ˜์Œ์œผ๋กœ ๋Œ์•„์™€ ํ•œ ์ค„์”ฉ ํ‰๊ฐ€๋ฅผ ์‹œ์ž‘ํ•˜๋Š”๋ฐ, ํ‰๊ฐ€ํ•˜๋Š” ์ฝ”๋“œ์ค„์—์„œ a์— ๊ฐ’์ด ํ• ๋‹น๋˜๊ฑฐ๋‚˜, console.log(a)๊ณผ ๊ฐ™์ด ์‚ฌ์šฉ๋  ๋•Œ, ๋ฏธ๋ฆฌ ์ˆ˜์ง‘ํ•ด๋‘” ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์™€์„œ ๊ฐ’์„ ์ƒˆ๋กœ ์ €์žฅํ•˜๊ณ , ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด๋‹ค.

๊ทธ๋ ‡๊ธฐ ๋•Œ๋ฌธ์— ํ•จ์ˆ˜ ํ˜ธ์ถœ ์ „์— ๋‹ด๊ธด ์ •๋ณด๋กœ๋Š” ๋‹ค๋ฅธ ํ•จ์ˆ˜ ๋‚ด๋ถ€์˜ ๋ณ€์ˆ˜๋ฅผ ์•Œ ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์ด ์—†๋‹ค ๊ทธ๋ž˜์„œ ๊ฐ ํ•จ์ˆ˜๋Š” ๊ณ ์œ ํ•œ ์Šค์ฝ”ํ”„๋ฅผ ๊ฐ€์ง€๊ฒŒ ๋œ๋‹ค. (es6์—์„œ๋Š” while, if, for๋ฌธ ๊ฐ™์€ ํ•จ์ˆ˜๊ฐ€ ์•„๋‹Œ ๋ธ”๋ก๋ฌธ์—์„œ๋„ ์ƒˆ๋กœ ์Šค์ฝ”ํ”„๋ฅผ ๋งŒ๋“ฆ.) ์ด๋ ‡๊ฒŒ ๋งŒ๋“ค์–ด์ง„ ์Šค์ฝ”ํ”„๋Š” ํ•จ์ˆ˜๊ฐ€ ์ข…๋ฃŒ๋˜๋ฉด์„œ ์‚ฌ๋ผ์ง€๊ฒŒ ๋œ๋‹ค.

Scope Chain

์Šค์ฝ”ํ”„ ๋‚ด๋ถ€์—์„œ ์„ ์–ธ๋œ ํ•จ์ˆ˜์˜ ์‹๋ณ„์ž๋Š” ์•Œ์ˆ˜ ์—†์ง€๋งŒ ์Šค์ฝ”ํ”„ ๋ฐ”๊นฅ์˜ ์‹๋ณ„์ž๋Š” ์•Œ ์ˆ˜ ์žˆ๋‹ค.

function outer() {
  const outer = "outer!";

  function inner() {
    console.log(outer);
  }

  inner(); // outer!
}

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋Š” ์Šค์ฝ”ํ”„ ๋‚ด์— ์ฐธ์กฐํ•  ์ˆ˜ ์žˆ๋Š” ๋ณ€์ˆ˜๋‚˜ ํ•จ์ˆ˜๊ฐ€ ์กด์žฌํ•˜์ง€ ์•Š์œผ๋ฉด ๋ฐ”๊นฅ์˜ ์Šค์ฝ”ํ”„์—์„œ ์‹๋ณ„์ž ์ •๋ณด๋ฅผ ์ฐพ๋Š”๋‹ค.

์ด๊ฒƒ์ด ๊ฐ€๋Šฅํ•œ ์ด์œ ๋Š”, ์•ž์„œ ๋งํ–ˆ๋˜ ํ•จ์ˆ˜ ํ‰๊ฐ€ ์ด์ „์— ์ญ‰ ํ›‘๋Š” ๊ณผ์ •(๋ณ€์ˆ˜ ์„ ์–ธ, ํ•จ์ˆ˜์„ ์–ธ ์ˆ˜์ง‘) ์ด์™ธ์— ๋ฐ”๊นฅ ์Šค์ฝ”ํ”„์— ๋Œ€ํ•œ ์ •๋ณด๋ฅผ ์ˆ˜์ง‘ํ•˜๋Š” ๊ณผ์ •๋„ ์žˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. (์‹คํ–‰์ปจํ…์ŠคํŠธ์˜ outerEnvironmentReference์—์„œ ํ•ด๋‹น ์‹คํ–‰์ปจํ…์ŠคํŠธ์˜ ๋ ‰์‹œ์ปฌํ™˜๊ฒฝ์˜ ํ™˜๊ฒฝ๋ ˆ์ฝ”๋“œ๋ฅผ ์ฐธ์กฐํ•˜๊ฒŒ๋œ๋‹ค.)

function furtherOuter() {
  const furtherOuterVariable = "further outer!";

  function outer() {
    function inner() {
      console.log(furtherOuterVariable);
    }

    inner(); // further outer!
  }
}

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์—”์ง„์€ ์Šค์ฝ”ํ”„ ์•ˆ์— ์ฐธ์กฐํ•˜๋Š” ์‹๋ณ„์ž ์ •๋ณด๊ฐ€ ์—†๋‹ค๋ฉด ํ•จ์ˆ˜ ํ‰๊ฐ€ ์ „์— ์ˆ˜์ง‘ํ–ˆ๋˜ ๋ฐ”๋กœ ๋ฐ”๊นฅ ์Šค์ฝ”ํ”„๋กœ ๊ฐ€์„œ ์‹๋ณ„์ž๋ฅผ ์ฐพ๋Š”๋‹ค. ๋ฐ”๋กœ ๋ฐ”๊นฅ ์Šค์ฝ”ํ”„์—๋„ ์ฐพ๋Š” ์‹๋ณ„์ž๊ฐ€ ์—†๋‹ค๋ฉด, ๊ทธ ๋‹ค์Œ ์Šค์ฝ”ํ”„๋กœ ๊ฐ€์„œ ์ฐพ๊ณ , ๋งˆ์ง€๋ง‰์—” ์ „์—ญ ์Šค์ฝ”ํ”„๊นŒ์ง€ ๊ฐ€์„œ ์ฐพ๋Š”๋ฐ ์ด๋•Œ๋„ ์กด์žฌํ•˜์ง€ ์•Š๋Š”๋‹ค๋ฉด ์ฐธ์กฐ์—๋Ÿฌ ๋ฅผ ๋ฐœ์ƒ์‹œํ‚จ๋‹ค. ์ด๋ ‡๊ฒŒ ์Šค์ฝ”ํ”„๊ฐ€ ์ฒด์ธ์ฒ˜๋Ÿผ ์—ฐ๊ฒฐ ๋˜์–ด์žˆ๋Š” ๊ฒƒ์„ ์Šค์ฝ”ํ”„์ฒด์ธ์ด๋ผ๊ณ  ํ•œ๋‹ค.

โš ๏ธ ์ด๋•Œ ์ฃผ์˜ํ•ด์•ผํ•  ๊ฒƒ์€ ๋ฐ”๋กœ ๋ฐ”๊นฅ ์Šค์ฝ”ํ”„๋Š” ํ•จ์ˆ˜๋ฅผ ์‹คํ–‰ํ•˜๋Š” ์‹œ์ ์˜ ๋ฐ”๊นฅ์˜์—ญ์ด ์•„๋‹Œ ์„ ์–ธ๋˜๋Š” ์‹œ์ ์˜ ๋ฐ”๊นฅ ์Šค์ฝ”ํ”„๋ฅผ ๊ฐ€๋ฆฌํ‚จ๋‹ค. (๋ ‰์‹œ์ปฌ ์Šค์ฝ”ํ”„)

function scopeA() {
  const a = "ํ˜ธ๋ž‘์ด"; // ์„ ์–ธ ์‹œ์ ์˜ ์ƒ์œ„ ์Šค์ฝ”ํ”„

  function scopeB() {
    console.log(a);
  }

  return scopeB;
}

const scopeC = scopeA();

const a = "๊ธฐ๋ฆฐ"; // ์‹คํ–‰ ์‹œ์ ์˜ ์ƒ์œ„ ์Šค์ฝ”ํ”„(?)

scopeC(); // 'ํ˜ธ๋ž‘์ด'

Closure ๐Ÿšซ

const outer = () => {
  const out = "outer!"; // 1. ๋ฐ”๊นฅ ํ•จ์ˆ˜ outer์˜ ์Šค์ฝ”ํ”„์— ๋ณ€์ˆ˜์„ ์–ธ

  const inner = () => {
    console.log(out); // 2. ๋‚ด๋ถ€ ํ•จ์ˆ˜ inner์˜ ์Šค์ฝ”ํ”„์—์„œ ์Šค์ฝ”ํ”„์ฒด์ธ์„ ํƒ€๊ณ  ๋ฐ”๊นฅ ํ•จ์ˆ˜ ์Šค์ฝ”ํ”„์˜ ๋ณ€์ˆ˜ ์ฐธ์กฐ
  };

  return inner; // 3. 1๊ธ‰ ์‹œ๋ฏผ์ธ ํ•จ์ˆ˜ inner๋ฅผ ๋ฐ”๊นฅ์œผ๋กœ ๋ฐ˜ํ™˜
};

const foo = outer(); // 4.  foo์— innerํ•จ์ˆ˜์˜ ์ฃผ์†Œ๊ฐ’์ด ์ €์žฅ๋จ

foo(); // 5. outerํ•จ์ˆ˜ ํ˜ธ์ถœ์€ ์ข…๋ฃŒ๊ฐ€ ๋˜์–ด์„œ ์Šค์ฝ”ํ”„๊ฐ€ ์‚ฌ๋ผ์ ธ์•ผ ํ•˜์ง€๋งŒ out์€ ์—ฌ์ „ํžˆ ์ž˜ ์ฐธ์กฐ๋œ๋‹ค.

ํด๋กœ์ ธ๋Š” ์–ด๋–ค ํ•จ์ˆ˜(outer) ๋‚ด๋ถ€์— ์„ ์–ธ๋œ ํ•จ์ˆ˜(inner)๊ฐ€ ๋ฐ”๊นฅ ํ•จ์ˆ˜(outer)์˜ ์ง€์—ญ๋ณ€์ˆ˜(outerVariable)๋ฅผ ์ฐธ์กฐํ•˜๋Š” ๊ฒƒ์ด ํ•จ์ˆ˜(outer)๊ฐ€ ์ข…๋ฃŒ๋œ ์ดํ›„์—๋„ ๊ณ„์† ์œ ์ง€๋˜๋Š” ํ˜„์ƒ์„ ๋งํ•œ๋‹ค.

๐Ÿ’ก outer ํ•จ์ˆ˜ ๋ฐ”๊นฅ์œผ๋กœ ๋ฐ˜ํ™˜๋œ innerํ•จ์ˆ˜๊ฐ€ outer ํ•จ์ˆ˜์˜ outerVariable ๋ณ€์ˆ˜๋ฅผ ์ฐธ์กฐํ•˜๊ธฐ์— ๋ฉ”๋ชจ๋ฆฌ์— outer์˜ ์Šค์ฝ”ํ”„๊ฐ€ ์—ฌ์ „ํžˆ ๋‚จ์•„์žˆ๋‹ค.

Closure ์‘์šฉ

  1. ํ•จ์ˆ˜๋ฅผ ์—ฌ๋Ÿฌ๋ฒˆ ํ˜ธ์ถœํ•˜๋ฉด ์ƒํƒœ๊ฐ€ ์—ฐ์†์ ์œผ๋กœ ์œ ์ง€๋  ๋•Œ
function outer() {
  let value = 0;

  return {
    increase() {
      ++value;
      console.log(value);
    },
    decrease() {
      --value;
      console.log(value);
    },
  };
}

const count = outer();
count.increase(); // 1
count.increase(); // 2
count.increase(); // 3
count.decrease(); // 2
count.decrease(); // 1
count.decrease(); // 0
console.log(value); // Error

์œ„์™€ ๊ฐ™์ด ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด ์ด์ „ ํ•จ์ˆ˜ ํ˜ธ์ถœ ์ƒํƒœ๊ฐ€ ๊ธฐ์–ต๋˜๊ธธ ๋ฐ”๋ž„ ๋•Œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

์‹ค์ œ ์‚ฌ๋ก€๋กœ ํ”„๋ก ํŠธ์—”๋“œ ํ”„๋ ˆ์ž„์›Œํฌ์ธ React ์˜ hook API๊ฐ€ ํด๋กœ์ ธ๋ฅผ ํ†ตํ•ด์„œ ๊ตฌํ˜„๋˜์—ˆ๋‹ค.

hook์€ ํ•จ์ˆ˜๋ฅผ ์—ฌ๋Ÿฌ ๋ฒˆ ํ˜ธ์ถœํ•˜๋Š” ์ƒํ™ฉ์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ์—ฐ์†์ ์œผ๋กœ ์œ ์ง€ํ•˜๋Š” ๊ธฐ๋Šฅ์ด๋‹ค.

const Counter = () => {
  const [value, setValue] = useState(0); // ์ด hookํ•จ์ˆ˜๊ฐ€ ํด๋กœ์ ธ๋ฅผ ํ†ตํ•ด ๊ตฌํ˜„๋˜์—ˆ๋‹ค.

  return (
    <div>
      <p>{value}</p>
      <button onClick={() => setValue(value + 1)}>+</button>
      <button onClick={() => setValue(value - 1)}>-</button>
    </div>
  );
};

์ƒํƒœvalue๊ฐ€ ๋ฐ”๋€Œ์–ด ๋ Œ๋”๋ง์ด ๊ณ„์† ์ผ์–ด๋‚จ์— ๋”ฐ๋ผ Counter ํ•จ์ˆ˜๊ฐ€ ์—ฌ๋Ÿฌ ๋ฒˆ ํ˜ธ์ถœ๋œ๋‹ค. ํ•˜์ง€๋งŒ useState๋Š” 0์ด ์•„๋‹ˆ๋ผ ์ด์ „ ์ƒํƒœ value์˜ ๊ฐ’์„ ์œ ์ง€ํ•˜๊ณ  ์žˆ๋‹ค. ์ด๋Š” useState ์„ ์–ธ ์‹œ์ ์˜ ๋ฐ”๊นฅ ๋ณ€์ˆ˜์— 0์„ ์ดˆ๊ธฐํ™”ํ•œ ๋‹ค์Œ, setValue๋กœ ํ•ด๋‹น ๋ฐ”๊นฅ ๋ณ€์ˆ˜๋ฅผ ๋ณ€๊ฒฝํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋‹ค์Œ Counter๊ฐ€ ํ˜ธ์ถœ๋˜๊ณ  ๊ทธ ์•ˆ์˜ useState๊ฐ€ ๋‹ค์‹œ ํ˜ธ์ถœ๋˜๋ฉด ๋ณ€๊ฒฝ๋œ ๋ฐ”๊นฅ ๋ณ€์ˆ˜๋ฅผ value๋กœ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

  1. ๋ณ€์ˆ˜๋ฅผ ์ˆจ๊ฒจ์•ผ ํ•  ๋•Œ
let value = 0;

function increase() {
  console.log(++value);
}

function decrease() {
  console.log(--value);
}

function unknown() {
  value = -100000;
}

increase(); // 1
unknown(); // value: -100000
decrease(); // -100001

์ „์—ญ ๋ณ€์ˆ˜๋กœ ์„ ์–ธํ•ด์„œ ์‚ฌ์‹ค ์œ„์™€ ๊ฐ™์€ ํด๋กœ์ ธ๋ฅผ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์ด ์žˆ๊ธด ์žˆ์œผ๋‚˜ ๋งŒ์•ฝ ์ฝ”๋“œ์˜ ์–‘์ด ๋งŽ์•„์ง€๊ณ  ๊ธธ์–ด์ง€๊ฒŒ ๋œ๋‹ค๋ฉด ์–ด๋””์„œ ํ•ด๋‹น ์ „์—ญ๋ณ€์ˆ˜์˜ ์ƒํƒœ๋ฅผ ๊ด€๋ฆฌํ•˜๋Š”์ง€ ์ถ”์ ์ด ์–ด๋ ค์›Œ์ง€๊ฒŒ ๋˜๊ณ  ๊ฐ€๋…์„ฑ๊ณผ ์œ ์ง€๋ณด์ˆ˜์— ์–ด๋ ค์›€์„ ๊ฒช๊ฒŒ ํ•œ๋‹ค.

const counterCreator = () => {
  let value = 0;

  return {
    increase() {
      console.log(++value);
    },
    decrease() {
      console.log(--value);
    },
  };
};

const counter = counterCreator();

function unknown() {
  value = -100000;
}

counter.increase(); // 1
unknown(); // error: Uncaught ReferenceError: value is not defined
counter.decrease(); // ์ •์ƒ์ ์œผ๋กœ ์ง„ํ–‰๋œ๋‹ค๋ฉด 0

์œ„์™€ ๊ฐ™์ด ํด๋กœ์ €๋กœ ํ•จ์ˆ˜๋ฅผ ๋งŒ๋“ค๋ฉด ์™ธ๋ถ€์—์„œ ๋ณ€์ˆ˜์— ์ ‘๊ทผ์‹œ ๋ ˆํผ๋Ÿฐ์Šค ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

  1. ํ•จ์ˆ˜๊ฐ€ ๋…๋ฆฝ์ ์œผ๋กœ ๋™์ž‘ํ•ด์•ผํ•  ๋•Œ

์นด์šดํ„ฐ๋ฅผ ๋‘ ๊ฐ€์ง€ ๋…๋ฆฝ์ ์œผ๋กœ ํ•ด์•ผํ•˜๋Š” ์ƒํ™ฉ์ด ์žˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•˜์ž

let myValue = 0;
let yourValue = 0;

function increaseMyCounter() {
  console.log(++myValue);
}

function decreaseMyCounter() {
  console.log(--myValue);
}

function increaseYourCounter() {
  console.log(++yourValue);
}

function decreaseYourCounter() {
  console.log(--yourValue);
}

์ด๋ ‡๊ฒŒ ํ•ด๋ฒ„๋ฆฌ๋ฉด ์ฝ”๋“œ๊ฐ€ ๋„ˆ๋ฌด ๊ธธ์–ด์ง€๊ณ  ์ง€์ €๋ถ„ํ•ด ๋ณด์ธ๋‹ค.

๊ทธ๋Ÿฌ๋ฉด ํด๋กœ์ ธ๋กœ ๋งŒ๋“ค์–ด๋ณด์ž

const counterCreator = () => {
  let value = 0;

  return {
    increase() {
      console.log(++value);
    },
    decrease() {
      console.log(--value);
    },
  };
};

const myCounter = counterCreator();
const yourCounter = counterCreator();

myCounter.increase(); // 1
myCounter.increase(); // 2
yourCounter.increase(); // 1
myCounter.decrease(); // 1

์œ„์™€ ๊ฐ™์ด myCounter์™€ yourCounter์˜ ์ƒํƒœ๋Š” ๋…๋ฆฝ์ ์ด๊ฒŒ ๋˜์—ˆ๋‹ค.

๐Ÿ” ํด๋กœ์ €๋ฅผ ํ™œ์šฉํ•ด ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— ๊ฐ€๋…์„ฑ์ด ํ›จ์”ฌ ์ข‹์•„์ง„ ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.