Understand Closures in JavaScript - Lee-hyuna/33-js-concepts-kr GitHub Wiki

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ํด๋กœ์ ธ ์ดํ•ด

ํด๋กœ์ €๋Š” ๋ณต์žกํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋‹จ 10๋ถ„๋งŒ์— ํด๋กœ์ €์˜ ๊ธฐ์ดˆ๋ฅผ ๋ฐฐ์šฐ๊ณ  ์ดํ•ด ํ•ด๋ด…์‹œ๋‹ค.

ํด๋กœ์ €๋Š” ๋ฌด์—‡์ž…๋‹ˆ๊นŒ?

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

์šฐ๋ฆฌ๋Š” ํด๋กœ์ €์— ๋Œ€ํ•œ ๋‘ ๊ฐ€์ง€ ๊ต๊ณผ์„œ ์ •์˜๋ฅผ ์‚ดํŽด ๋ณผ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์ •์˜ #1

ํด๋กœ์ €๋Š” ์Šค์ฝ”ํ”„๊ฐ€ ๋‹ซํžŒ ํ›„์—๋„ ์ƒ์œ„ ์Šค์ฝ”ํ”„์— ์ ‘๊ทผ ํ•  ์ˆ˜ ์žˆ๋Š” ํ•จ์ˆ˜์ž…๋‹ˆ๋‹ค.

์ •์˜ #2

ํด๋กœ์ €๋Š” ํ•จ์ˆ˜์™€ ํ•ด๋‹น ํ•จ์ˆ˜๊ฐ€ ์„ ์–ธ๋œ 'lexical environment'์˜ ์กฐํ•ฉ์ž…๋‹ˆ๋‹ค.

์ข‹์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์‹ค์ œ๋กœ ๋ฌด์—‡์„ ์˜๋ฏธํ• ๊นŒ์š”?

๋จผ์ € ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์˜ ์Šค์ฝ”ํ”„๋ฅผ ์ดํ•ดํ•ด์•ผ๋ฉ๋‹ˆ๋‹ค. ์Šค์ฝ”ํ”„๋Š” ๋ณธ์งˆ์ ์œผ๋กœ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์—์„œ ๋ณ€์ˆ˜์˜ ์ˆ˜๋ช…์ž…๋‹ˆ๋‹ค. ๋ณ€์ˆ˜๊ฐ€ ์ •์˜ ๋œ ์œ„์น˜๋Š” ํ•ด๋‹น ๋ณ€์ˆ˜์˜ ์ง€์† ์‹œ๊ฐ„๊ณผ ํ”„๋กœ๊ทธ๋žจ์˜ ํ•จ์ˆ˜์— ์ ‘๊ทผํ•˜๋Š”๋ฐ ํฐ ์—ญํ• ์„ ํ•ฉ๋‹ˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด ๋ด…์‹œ๋‹ค.

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋กœ ํ•จ์ˆ˜๋ฅผ ์ž‘์„ฑํ•˜๋ฉด ํ•จ์ˆ˜ ๋‚ด๋ถ€ ๋ฐ ์™ธ๋ถ€์—์„œ ์ž‘์„ฑ๋œ ๋ณ€์ˆ˜์— ์ ‘๊ทผ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

ํ•จ์ˆ˜ ๋‚ด์—์„œ ์ƒ์„ฑ ๋œ ๋ณ€์ˆ˜๋Š” ๋กœ์ปฌ๋กœ ์ •์˜๋œ ๋ณ€์ˆ˜์ž…๋‹ˆ๋‹ค. ์ง€์—ญ๋ณ€์ˆ˜๋Š” ์ •์˜๋œ ํ•จ์ˆ˜(์Šค์ฝ”ํ”„) ๋‚ด์—์„œ๋งŒ ์ ‘๊ทผ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์•„๋ž˜ ์˜ˆ์ œ์—์„œ ํ•จ์ˆ˜ ์™ธ๋ถ€์˜ words ๊ฐ’์„ ๊ธฐ๋กํ•˜๋ ค๊ณ  ํ•˜๋ฉด ์ฐธ์กฐ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒ ํ•จ์„ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. words๋Š” ์ง€์—ญ ์Šค์ฝ”ํ”„๊ฐ€ ์ง€์ •๋œ ๋ณ€์ˆ˜ ์ด๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

// Example of accessing variables INSIDE the function
// words is a LOCAL variable
function speak(){
  var words = 'hi'; 
  console.log(words);
}
speak(); // 'hi'
console.log(words); // Uncaught ReferenceError: words is not defined

์ด ์˜ˆ์ œ์™€๋Š” ๋Œ€์กฐ์ ์œผ๋กœ, ์šฐ๋ฆฌ๊ฐ€ ์ „์—ญ ์Šค์ฝ”ํ”„์—์„œ words๋ฅผ ์ •์˜ํ•˜๋Š” ๊ฒฝ์šฐ ๋ฌธ์„œ์˜ ๋ชจ๋“  ํ•จ์ˆ˜์— ์ ‘๊ทผ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

// Example of accessing variables OUTSIDE the function
// words is a GLOBAL variable
var words = 'hi';
function speak(){ 
  console.log(words);
}
speak(); // 'hi' 
console.log(words); // 'hi'

Nested Functions

ํ•œ ํ•จ์ˆ˜๋ฅผ ๋‹ค๋ฅธ ํ•จ์ˆ˜ ์•ˆ์— ์ค‘์ฒฉํ•˜๋ฉด ์–ด๋–ป๊ฒŒ ๋ฉ๋‹ˆ๊นŒ?
์ด ์˜ˆ์ œ๊ฐ€ ์žฌ๋ฏธ์žˆ์–ด์ง€๊ธฐ ๋•Œ๋ฌธ์— ๋‹ค์Œ ์˜ˆ์ œ๋ฅผ ๋”ฐ๋ผ๊ฐ€ ๋ณด์‹ญ์‹œ์˜ค.

Chrome์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ ์ฝ˜์†”์ฐฝ ์—ฌ๋Š” ๋ฐฉ๋ฒ• [WINDOWS] : Ctrl + Shift + J
[MAC] : Cmd + Opt + J

cool. ์ด์ œ ์•„๋ž˜ ์ฝ”๋“œ๋ฅผ ๋ณต์‚ฌํ•˜์—ฌ ์ฝ˜์†”์ฐฝ์— ๋ถ™์—ฌ ๋„ฃ์Šต๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๋Š” speak๋ผ๋Š” ํ•จ์ˆ˜๋ฅผ ๋งŒ๋“œ๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. speak๋Š” logIt์ด๋ผ๋Š” ํ•จ์ˆ˜๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. ๋งˆ์ง€๋ง‰์œผ๋กœ logIt์€ words์˜ ๊ฐ’์„ ์ฝ˜์†”์— ๊ธฐ๋กํ•ฉ๋‹ˆ๋‹ค. ์ด ๊ฒฝ์šฐ ์ฝ˜์†”์— 'hi'๋ฅผ ๊ธฐ๋กํ•ฉ๋‹ˆ๋‹ค.

function speak() {
  return function logIt() {
    var words = 'hi';
    console.log(words);
  }
}

์ฝ˜์†”์— ๋ณต์‚ฌ ํ•œ ํ›„ ๋ณ€์ˆ˜๋ฅผ ๋งŒ๋“ค์–ด speakํ•จ์ˆ˜๋ฅผ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ํ• ๋‹นํ•ฉ๋‹ˆ๋‹ค:

var sayHello = speak();

์ด์ œ ์šฐ๋ฆฌ๋Š” ๋ณ€์ˆ˜๋ฅผ ๋ถ€๋ฅด์ง€๋งŒ ๋‚ด๋ถ€ ํ•จ์ˆ˜์„ ๋ถˆ๋Ÿฌ๋“ค์ด์ง€ ์•Š์•„๋„ sayHello์˜ ๊ฐ’์ด ๋ฌด์—‡์ธ์ง€ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

sayHello;
//  function logIt() {
//    var words = 'hi';
//    console.log(words);
//  }

์˜ˆ์ƒ๋Œ€๋กœ sayHello๋Š” ๋ฐ˜ํ™˜๋œ ๋‚ด๋ถ€ ํ•จ์ˆ˜๋ฅผ ์ฐธ์กฐํ•ฉ๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ์ฝ˜์†”์—์„œ sayHello()๋ฅผ ์‹คํ–‰ํ•˜๋ฉด logIt()ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๊ณ  ์‹คํ–‰ํ•œ๋‹ค๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค:

sayHello();
// 'hi'

ํšจ๊ณผ๊ฐ€ ์žˆ์–ด! ๊ทธ๋Ÿฌ๋‚˜ ์ด๊ฒƒ์€ ํŠน๋ณ„ํ•œ ๊ฒƒ์€ ์•„๋‹™๋‹ˆ๋‹ค. ํ•œ ์ค„์˜ ์ฝ”๋“œ๋ฅผ ์›€์ง์—ฌ์„œ ์–ด๋–ค ๋ณ€ํ™”๊ฐ€ ์žˆ๋Š”์ง€ ๋ด…์‹œ๋‹ค. ์•„๋ž˜ ์˜ˆ์ œ๋ฅผ ์‚ดํŽด๋ณด์‹ญ์‹œ์˜ค.
๋ณ€์ˆ˜ words ์„ ์–ธ์„ ๋‚ด๋ถ€ํ•จ์ˆ˜์—์„œ ์™ธ๋ถ€speak()ํ•จ์ˆ˜๋กœ ์˜ฎ๊ฒผ์Šต๋‹ˆ๋‹ค:

function speak() {
  var words = 'hi';
  return function logIt() {
    console.log(words);
  }
}

์ด์ „๊ณผ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ๋ณ€์ˆ˜๋ฅผ ์„ ์–ธํ•˜๊ณ  speakํ•จ์ˆ˜์— ํ• ๋‹นํ•ฉ๋‹ˆ๋‹ค :

var sayHello = speak();

์ด์ œ sayHello๋ณ€์ˆ˜๊ฐ€ ๋ฌด์—‡์„ ์ฐธ์กฐํ•˜๋Š”์ง€ ์‚ดํŽด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค :

sayHello
//  function logIt() {
//    console.log(words);
//  }

Uh oh. words ๋ณ€์ˆ˜ ์ •์˜๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด ์–ด๋–ป๊ฒŒ ๋ ๊นŒ์š”?

sayHello();
// 'hi'

์—ฌ์ „ํžˆ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค! ํด๋กœ์ €์˜ ํšจ๊ณผ๋ฅผ ๋ฐฉ๊ธˆ ๊ฒฝํ—˜ํ–ˆ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

ํ˜ผ๋ž€์Šค๋Ÿฌ์šด๊ฐ€์š”? ๊ดœ์ฐฎ์Šต๋‹ˆ๋‹ค. ํด๋กœ์ € ์ •์˜๋ฅผ ๋‹ค์‹œ ์ƒ๊ฐํ•ด๋ณด์‹ญ์‹œ์˜ค.

ํด๋กœ์ €๋Š” ๋ฒ”์œ„๊ฐ€ ๋‹ซํžŒ ํ›„์—๋„ ์ƒ์œ„ ์Šค์ฝ”ํ”„์— ์ ‘๊ทผ ํ•  ์ˆ˜์žˆ๋Š” ํ•จ์ˆ˜์ž…๋‹ˆ๋‹ค.  

์ด ๊ฒฝ์šฐ speak()ํ•จ์ˆ˜์˜ ์Šค์ฝ”ํ”„๊ฐ€ ๋‹ซํ˜”์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ var words = 'hi'๋„ ์‚ฌ๋ผ์ ธ์•ผ ํ•จ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์—๋Š” ํด๋กœ์ €๋ผ๋Š” ๋ฉ‹์ง„ ์ž‘์€ ๊ฐœ๋…์ด ์žˆ์Šต๋‹ˆ๋‹ค. ๋‚ด๋ถ€ ํ•จ์ˆ˜๋Š” ์ƒ์„ฑ๋œ ๋ฒ”์œ„์— ๋Œ€ํ•œ ์ฐธ์กฐ๋ฅผ ์œ ์ง€ํ•ฉ๋‹ˆ๋‹ค. ์ด๋ ‡๊ฒŒํ•˜๋ฉด speak()๊ฐ€ ๋‹ซํžŒ ํ›„์—๋„ logIt ()ํ•จ์ˆ˜๊ฐ€ words๋ณ€์ˆ˜์— ๊ณ„์† ์ ‘๊ทผ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

function speak() {
  var words = 'hi';
  return function logIt() {
    console.log(words);
  }
}

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์˜ ๋ชจ๋“  ํ•จ์ˆ˜์—๋Š” ํด๋กœ์ €๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ๊ธฐ๋Šฅ์„ ์ž‘๋™์‹œํ‚ค๊ธฐ ์œ„ํ•ด ํ•จ์ˆ˜์— ๋Œ€ํ•ด ๋ช…์‹œ์ ์œผ๋กœ ํ•  ํ•„์š”๋Š” ์—†์Šต๋‹ˆ๋‹ค. ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์˜ ์ผ๋ถ€์ผ ๋ฟ์ž…๋‹ˆ๋‹ค.

Example #2

๋‹ค๋ฅธ ์˜ˆ๋ฅผ ์‚ดํŽด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ์กฐ๊ธˆ ๋” ๋ณต์žกํ•ฉ๋‹ˆ๋‹ค. ์ฝ”๋“œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค :

function name(n) {
  return function(a) {
    return `${n} likes ${a}`;
  };
}

ํ•˜๋‚˜์˜ ๋งค๊ฐœ ๋ณ€์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ๋‹ค๋ฅธ ๋งค๊ฐœ ๋ณ€์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์ต๋ช… ํ•จ์ˆ˜๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” nameํ•จ์ˆ˜๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ๋‚ด๋ถ€ ํ•จ์ˆ˜์˜ ๊ฒฐ๊ณผ๋Š” ๋ฌธ์ž์—ด์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

nameํ•จ์ˆ˜๋ฅผ ๋‘ ๋ฒˆ ํ˜ธ์ถœ ํ•ด๋ด…์‹œ๋‹ค. ํ•˜๋‚˜๋Š” John์ด๋ผ๋Š” ์ด๋ฆ„์„, ๋‹ค๋ฅธ ํ•˜๋‚˜๋Š” Cindy๋ฅผ ์ „๋‹ฌํ•ฉ๋‹ˆ๋‹ค.

var j = name('John');
var c = name('Cindy')

์ด์ œ j๊ฐ€ ๋ฌด์—‡์„ ์ฐธ์กฐํ•˜๋Š”์ง€ ์ •ํ™•ํžˆ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค :

j;
//  function (a) {
//    return `${n} likes ${a}`;
//  }

๋Œ€๋‹จํ•ฉ๋‹ˆ๋‹ค! ์ด์ „ ์˜ˆ์ œ์—์„œ ํด๋กœ์ €๋กœ ์ธํ•ด ํ•จ์ˆ˜๊ฐ€ ์—ฌ์ „ํžˆ ์ƒ์œ„ ์Šค์ฝ”ํ”„์—์„œ n๋ณ€์ˆ˜์— ์ ‘๊ทผ ํ•  ์ˆ˜ ์žˆ์–ด์•ผ ํ•œ๋‹ค๋Š” ๊ฒƒ์„ ์•Œ๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœ ํ•  ๋•Œ ๊ฐ’์„ ์ „๋‹ฌํ•˜๋ฉด๋ฉ๋‹ˆ๋‹ค. ์‹œ๋„ํ•ด ๋ด…์‹œ๋‹ค :

j('dogs');  // 'John likes dogs'
c('cats');  // 'Cindy likes cats'

์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค! ํด๋กœ์ €๋กœ ์ธํ•ด ์ด์ „์— ๋‹ซํžŒ ์Šค์ฝ”ํ”„์˜ ๋ณ€์ˆ˜๋ฅผ ์ฐธ์กฐํ•˜๋Š” ํ•จ์ˆ˜๋ฅผ ์„ฑ๊ณต์ ์œผ๋กœ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋” ๋ฐœ์ „๋œ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋ฅผ ์›ํ•ฉ๋‹ˆ๊นŒ?

Check out: JavaScript: Understanding the Weird Parts

Closing Notes

ํด๋กœ์ €์˜ ๊ธฐ๋ณธ ์‚ฌํ•ญ์ด ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋กœ ์–ด๋–ป๊ฒŒ ์ž‘๋™ํ•˜๋Š”์ง€ ์ดํ•ดํ•  ์ˆ˜ ์žˆ๊ธฐ๋ฅผ ๋ฐ”๋ž๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ๋‹จ์ง€ ๋น™์‚ฐ์˜ ์ผ๊ฐ ์ผ๋ฟ์ž…๋‹ˆ๋‹ค. ์ด์ œ ํด๋กœ์ €์˜ ๋” ๋ณต์žกํ•˜๊ณ  ์‹ค์šฉ์ ์ธ ์˜ˆ์— ๋Œ€ํ•ด ๋ฐฐ์šธ ์ง€์‹์ด ์žˆ์Šต๋‹ˆ๋‹ค.