JavaScript Scope and Closures - Lee-hyuna/33-js-concepts-kr GitHub Wiki

Hello@

์Šค์ฝ”ํ”„์™€ ํด๋กœ์ €๋Š” ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์—์„œ ์•„~์ฃผ ์ค‘์š”ํ•œ ์—ญํ• ์„ ํ•˜์ฃ ? ๊ทธ๋Ÿฐ๋ฐ ์ฒ˜์Œ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋ฅผ ์ฒ˜์Œ ์‹œ์ž‘ํ• ๋• ์ง„์งœ ์ดํ•ดํ•˜๊ธฐ๊ฐ€ ์–ด๋ ค์šด ์ˆ™์ œ์ž…๋‹ˆ๋‹ค! ์ž์ž, ์ด์ œ ์Šค์ฝ”ํ”„์™€ ํด๋กœ์ €๊ฐ€ ๋ญ”์ง€ ์ง€๊ธˆ๋ถ€ํ„ฐ ๋นก์„ธ๊ฒŒ ์„ค๋ช…์„ ํ•ด๋“œ๋ฆฌ๊ฒ ์Šต๋‹ˆ๋‹ค

#Scope

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์˜ ์Šค์ฝ”ํ”„๋Š” ๋ณ€์ˆ˜์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋Š”๋ฐ '๊ธ€๋กœ๋ฒŒ ์Šค์ฝ”ํ”„'์™€ '๋กœ์ปฌ ์Šค์ฝ”ํ”„' ๋ฒ”์œ„๊ฐ€ ์žˆ๋‹ค.

#Global Scope

๋ชจ๋“  ๋ณ€์ˆ˜๊ฐ€ function ์ด๋‚˜ ์ค‘๊ด„ํ˜ธ {}๋กœ ๊ตฌ์„ฑ๋œ ๊ฐ์ฒด ์™ธ๋ถ€์— ์„ ์–ธ๋˜์—ˆ์„ ๋•Œ global scope๋ผ๊ณ  ํ•œ๋‹ค.

์ด๊ฑด ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์—์„œ๋งŒ ํ•ด๋‹นํ•œ๋‹ค. Node.js์—์„œ๋Š” ๊ธ€๋กœ๋ฒŒ ์Šค์ฝ”ํ”„๊ฐ€ ๋‹ค๋ฅด๊ฒŒ ์„ ์–ธ์ด ๋˜์ง€๋งŒ, ์ด ์ฑ•ํ„ฐ์—์„  Node.js๋ฅผ ํ•˜์ง€ ์•Š์œผ๋‹ˆ๊นŒ ํŒจ์“ฐ~ ๐Ÿ‘

const globalVariable = 'some value'

๊ธ€๋กœ๋ฒŒ ๋ณ€์ˆ˜๋กœ ์„ ์–ธ์ด ๋˜์—ˆ์œผ๋ฉด ์–ธ์ œ, ์–ด๋””์„œ๋“  ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

const hello = 'Hello CSS-Tricks Reader!'

function sayHello () {
  console.log(hello)
}

console.log(hello) // 'Hello CSS-Tricks Reader!'
sayHello() // 'Hello CSS-Tricks Reader!'

์ „์—ญ ๋ฒ”์œ„์—์„œ ๋ณ€์ˆ˜๋ฅผ ์„ ์–ธํ•  ์ˆ˜ ์žˆ์ง€๋งŒ, ๊ทธ๋Ÿฌ์ง€ ์•Š๋Š” ๊ฒƒ์ด ์ข‹๋‹ค. ๋‘ ๊ฐœ ์ด์ƒ์˜ ๋ณ€์ˆ˜๋ฅผ ๋™์ผํ•œ ์ด๋ฆ„์œผ๋กœ ๋ช…๋ช…ํ•˜๋Š” ์ถฉ๋Œ์˜ ๊ฐ€๋Šฅ์„ฑ์ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. const, let์œผ๋กœ ์„ ์–ธํ–ˆ๋‹ค๋ฉด ์ด๋ฆ„ ์ถฉ๋Œ์ด ์ผ์–ด๋‚  ๋•Œ๋งˆ๋‹ค ์˜ค๋ฅ˜๋ฅผ ๋ฐ›์„ ๊ฒƒ์ด๋‹ค. ์ด๋ ‡๊ฒŒ ํ•˜์ง€ ๋งˆ์„ธ์š”~!

// Don't do this!
let thing = 'something'
let thing = 'something else' // Error, thing has already been declared

var๋ฅผ ์„ ์–ธํ•˜๊ณ  ๋‘ ๋ฒˆ์งธ ๋ณ€์ˆ˜๋Š” ์„ ์–ธ๋œ ํ›„์— ์ฒซ๋ฒˆ์งธ ๋ณ€์ˆ˜๋ฅผ ๋ฎ์–ด์“ด๋‹ค. ์ด๊ฒƒ์€ ๋˜ํ•œ ์ฝ”๋“œ๋ฅผ ๋””๋ฒ„๊น…ํ•˜๊ธฐ ์–ด๋ ต๊ฒŒ ๋งŒ๋“ค๊ธฐ ๋•Œ๋ฌธ์— ๋ฐ”๋žŒ์งํ•˜์ง€ ์•Š๋‹ค.

// Don't do this!
var thing = 'something'
var thing = 'something else' // perhaps somewhere totally different in your code
console.log(thing) // 'something else'

๋”ฐ๋ผ์„œ ํ•ญ์ƒ ๊ธ€๋กœ๋ฒŒ ๋ณ€์ˆ˜๊ฐ€ ์•„๋‹ˆ๋ผ ๋กœ์ปฌ ๋ณ€์ˆ˜๋ฅผ ์„ ์–ธํ•ด์•ผ ํ•œ๋‹ค.

#Local Scope

์ฝ”๋“œ์˜ ํŠน์ • ๋ถ€๋ถ„์—์„œ๋งŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๋ณ€์ˆ˜๋Š” ๋กœ์ปฌ ๋ฒ”์œ„์— ์žˆ๋Š” ๊ฒƒ์œผ๋กœ ๊ฐ„์ฃผํ•œ๋‹ค. ์ด๋Ÿฌํ•œ ๋ณ€์ˆ˜๋ฅผ local scope๋ผ๊ณ ๋„ ํ•œ๋‹ค.

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์—๋Š” function scope์™€ block scope๋ผ๋Š” ๋‘ ์ข…๋ฅ˜์˜ local scope๊ฐ€ ์žˆ๋‹ค. ๋จผ์ € function scope๋ถ€ํ„ฐ ์ด์•ผ๊ธฐํ•ด ๋ด…์‹œ๋‹ค.

Function scope

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

function sayHello () {
  const hello = 'Hello CSS-Tricks Reader!'
  console.log(hello)
}

sayHello() // 'Hello CSS-Tricks Reader!'
console.log(hello) // Error, hello is not defined

Block scope

const์™€ let์€ ์ค‘๊ด„ํ˜ธ{}์•ˆ์—์„œ๋งŒ ์ ‘๊ทผ์ด ๊ฐ€๋Šฅํ•˜๋‹ค. ์•„๋ž˜์˜ ์˜ˆ์—์„œ๋Š” hello๊ฐ€ ์ค‘๊ด„ํ˜ธ ์•ˆ์—์„œ์˜ ์Šค์ฝ”ํ”„๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค.

{
  const hello = 'Hello CSS-Tricks Reader!'
  console.log(hello) // 'Hello CSS-Tricks Reader!'
}

console.log(hello) // Error, hello is not defined

(์•”๋ฌต์  ๋ฆฌํ„ด์ด ์žˆ๋Š” ํ™”์‚ดํ‘œ ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ํ•œ) ์ค‘๊ด„ํ˜ธ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ•จ์ˆ˜๋ฅผ ์„ ์–ธํ•ด์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋ธ”๋ก ์Šค์ฝ”ํ”„๋Š” ํ•จ์ˆ˜ ์Šค์ฝ”ํ”„์˜ ํ•˜์œ„ ์ง‘ํ•ฉ์ด๋‹ค.

#Function hoisting and scopes

ํ•จ์ˆ˜๋Š” ํ•จ์ˆ˜ ์„ ์–ธ๊ณผ ํ•จ๊ป˜ ์„ ์–ธ๋  ๋•Œ ํ•ญ์ƒ ํ˜„์žฌ ์Šค์ฝ”ํ”„์˜ ์ตœ์ƒ๋‹จ์œผ๋กœ ์˜ฌ๋ผ๊ฐ„๋‹ค. ๋”ฐ๋ผ์„œ ์ด ๋‘ ๊ฐ€์ง€๋Š” ๋™๋“ฑํ•˜๋‹ค.

// This is the same as the one below
sayHello()
function sayHello () {
  console.log('Hello CSS-Tricks Reader!')
}

// This is the same as the code above
function sayHello () {
  console.log('Hello CSS-Tricks Reader!')
}
sayHello()

ํ•จ์ˆ˜ ํ‘œํ˜„์‹์„ ์‚ฌ์šฉํ•˜์—ฌ ์„ ์–ธํ•  ๋•Œ ํ•จ์ˆ˜๋Š” ํ˜„์žฌ ์Šค์ฝ”ํ”„ ์ƒ๋‹จ์— ์˜ฌ๋ฆฌ์ง€ ์•Š๋Š”๋‹ค.

sayHello() // Error, sayHello is not defined
const sayHello = function () {
  console.log(aFunction)
}

์ด๋Ÿฌํ•œ ๋‘ ๊ฐ€์ง€ ๋ณ€ํ™” ๋•Œ๋ฌธ์— function ํ˜ธ์ด์ŠคํŒ…์€ ์ž ์žฌ์ ์œผ๋กœ ํ˜ผ๋™์„ ์ผ์œผํ‚ฌ ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ์‚ฌ์šฉํ•ด์„œ๋Š” ์•ˆ ๋œ๋‹ค. function์„ ์‚ฌ์šฉํ•˜๊ธฐ ์ „์— ํ•ญ์ƒ function์„ ์„ ์–ธํ•˜์‹ญ์‹œ์˜ค.

#Functions do not have access to each other's scopes

ํ•จ์ˆ˜๋Š” ํ•œ ํ•จ์ˆ˜๊ฐ€ ๋‹ค๋ฅธ ํ•จ์ˆ˜์— ์‚ฌ์šฉ๋  ์ˆ˜ ์žˆ์Œ์—๋„ ๋ถˆ๊ตฌํ•˜๊ณ  ๊ทธ๊ฒƒ๋“ค์„ ๋ณ„๋„๋กœ ์ •์˜ํ•  ๋•Œ ์„œ๋กœ์˜ ๋ฒ”์œ„์— ์ ‘๊ทผํ•  ์ˆ˜ ์—†๋‹ค. ๋‹ค์Œ ์•„๋ž˜์˜ ์˜ˆ์™€ ๊ฐ™์ด second ์—์„œ firstFunctionVariable๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋Š” ๋ถ€๋ถ„์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

function first () {
  const firstFunctionVariable = `I'm part of first`
}

function second () {
  first()
  console.log(firstFunctionVariable) // Error, firstFunctionVariable is not defined
}

<br>

### ##Nested scopes

ํ•จ์ˆ˜๊ฐ€ ๋‹ค๋ฅธ ํ•จ์ˆ˜์— ์ •์˜๋  ๋•Œ, ๋‚ด๋ถ€ ํ•จ์ˆ˜๋Š” ์™ธ๋ถ€ ํ•จ์ˆ˜์˜ ๋ณ€์ˆ˜์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด๋Ÿฌํ•œ ํ–‰๋™์„ ์–ดํœ˜์  ** lexical scoping**์ด๋ผ๊ณ  ํ•œ๋‹ค.<br>
๊ทธ๋Ÿฌ๋‚˜ ์™ธ์ธกํ•จ์ˆ˜๋Š” ๋‚ด์ธกํ•จ์ˆ˜์˜ ๋ณ€์ˆ˜์— ์ ‘๊ทผํ•  ์ˆ˜ ์—†๋‹ค.


```js
function outerFunction () {
  const outer = `I'm the outer function!`

  function innerFunction() {
    const inner = `I'm the inner function!`
    console.log(outer) // I'm the outer function!
  }

  console.log(inner) // Error, inner is not defined
}

์Šค์ฝ”ํ”„๊ฐ€ ์–ด๋–ป๊ฒŒ ์ž‘๋™ํ•˜๋Š”์ง€๋ฅผ ์‹œ๊ฐํ™”ํ•˜๊ธฐ ์œ„ํ•ด ์˜ˆ๋ฅผ ๋“ค์–ด๋ณด์ž ์ผ๋ฐฉ ์œ ๋ฆฌ๋ฅผ ์˜ˆ๋ฅผ ๋“ค์ž๋ฉด, ๊ฒ‰์€ ๋ณผ ์ˆ˜ ์žˆ์ง€๋งŒ ๊ฒ‰์€ ์‚ฌ๋žŒ์ด ๋ณผ ์ˆ˜ ์—†๋‹ค.

๋ฒ”์œ„ ๋‚ด์— ์Šค์ฝ”ํ”„๊ฐ€ ์žˆ๋Š” ๊ฒฝ์šฐ ์—ฌ๋Ÿฌ๊ฐ€์ง€ ์ธต์˜ ์ผ๋ฐฉ์œ ๋ฆฌ๋ฅผ ์ƒ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค.

์ง€๊ธˆ๊นŒ์ง€ ์Šค์ฝ”ํ”„์— ๋Œ€ํ•œ ๋ชจ๋“  ๊ฒƒ์„ ์ดํ•ดํ–ˆ๋‹ค๋ฉด ํด๋กœ์ €๊ฐ€ ๋ฌด์—‡์ธ์ง€ ์•Œ์•„๋‚ผ ์ค€๋น„๊ฐ€ ์ถฉ๋ถ„ํžˆ ๋˜์—ˆ๋‹ค.

Closures

ํ•จ์ˆ˜ ๋‚ด์—์„œ ๋‚ด๋ถ€ ํ•จ์ˆ˜๋ฅผ ์ƒ์„ฑํ•  ๋•Œ๋งˆ๋‹ค ํด๋กœ์ €๋ฅผ ์ƒ์„ฑํ•œ๋‹ค. ๋‚ด๋ถ€ํ•จ์ˆ˜๋Š” ํด๋กœ์ €๋‹ค. ํด๋กœ์ €๋Š” ๋ณดํ†ต ๋ฐ˜ํ™˜๋˜๋ฏ€๋กœ ์™ธ๋ถ€ํ•จ์ˆ˜์˜ ๋ณ€์ˆ˜๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. ํด๋กœ์ €๋ฅผ ๊ณต๋ถ€ํ•˜๋ฉด ํ•ญ์ƒ ๋ณผ ์ˆ˜ ์žˆ๋Š” ์˜ˆ์‹œ์ด๋‹ค.

function outerFunction () {
  const outer = `I see the outer variable!`

  function innerFunction() {
    console.log(outer)
  }

  return innerFunction
}

outerFunction()() // I see the outer variable!

์•„๋ž˜์˜ˆ์‹œ์ฒ˜๋Ÿผ ๋‚ด๋ถ€ํ•จ์ˆ˜๋Š” ๋ฆฌํ„ด๋˜๋ฏ€๋กœ ๊ธฐ๋Šฅ์„ ์„ ์–ธํ•˜๋ฉด์„œ ๋ฆฌํ„ด ์ž‘์„ฑํ•˜์—ฌ ์ฝ”๋“œ๋ฅผ ์•ฝ๊ฐ„ ๋‹จ์ถ•ํ•  ์ˆ˜๋„ ์žˆ๋‹ค.

function outerFunction () {
  const outer = `I see the outer variable!`

  return function innerFunction() {
    console.log(outer)
  }
}

outerFunction()() // I see the outer variable!

ํด๋กœ์ €๋Š” ์™ธ๋ถ€ํ•จ์ˆ˜์— ์žˆ๋Š” ๋ณ€์ˆ˜์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์ผ๋ฐ˜์ ์œผ๋กœ ๋‘ ๊ฐ€์ง€ ์šฉ๋„๋กœ ์‚ฌ์šฉ๋œ๋‹ค.

  1. ์‚ฌ์ด๋“œ ์ดํŽ™ํŠธ ์ปจํŠธ๋กค
  2. ๋ณ€์ˆ˜๋ฅผ ์•”ํ˜ธํ™” ํ•˜๋ ค๊ณ  ํ•  ๋•Œ

#Controlling side effects with closures

์‚ฌ์ด๋“œ ์ดํŽ™ํŠธ๋Š” ํ•จ์ˆ˜์˜ ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฒƒ ์™ธ์— ๋‹ค๋ฅธ ๊ฒƒ์„ ํ•  ๋•Œ ๋ฐœ์ƒํ•œ๋‹ค. Ajax ์š”์ฒญ, ์‹œ๊ฐ„ ์ดˆ๊ณผ ๋˜๋Š” console.log์™€ ๊ฐ™์€ ๋งŽ์€ ๊ฒƒ๋“ค์ด ๋ถ€์ž‘์šฉ์ผ ์ˆ˜ ์žˆ๋‹ค.

function (x) {
  console.log('A console.log is a side effect!')
}

๋ณดํ†ต ์‚ฌ์ด๋“œ ์ดํŽ™ํŠธ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ํด๋กœ์ €๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ Ajax๋‚˜ timeout์ฒ˜๋Ÿผ ์ฝ”๋“œํ๋ฆ„์„ ํ•ด์น ๊นŒ๋ด ๊ฑฑ์ •์„ ๋งŽ์ดํ•œ๋‹ค.

์ƒํ™ฉ์„ ๋” ๋ช…ํ™•ํ•˜๊ฒŒ ํ•˜๊ธฐ ์œ„ํ•ด ์ด ์ผ์„ ์˜ˆ์‹œ๋กœ ์‚ดํŽด๋ณด์ž.

์นœ๊ตฌ์˜ ์ƒ์ผ์„ ์œ„ํ•ด ์ผ€์ดํฌ๋ฅผ ๋งŒ๋“ค๊ณ  ์‹ถ๋‹ค๊ณ  ํ•˜์ž. ์ด ์ผ€์ดํฌ๋Š” ๋งŒ๋“œ๋Š” ๋ฐ 1์ดˆ๊ฐ€ ๊ฑธ๋ฆฌ๋‹ˆ๊นŒ 1์ดˆ ํ›„์— ๋กœ๊ทธ๋ฅผ Made a cake๋ผ๊ณ  ์ฐ๋Š”๋‹ค.

ES6 ํ™”์‚ดํ‘œ ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•˜์—ฌ ์˜ˆ๋ฅผ ๋” ์งง๊ณ  ์ดํ•ดํ•˜๊ธฐ ์‰ฝ๊ฒŒ ๋งŒ๋“ค๊ณ  ์žˆ๋‹ค.

function makeCake() {
  setTimeout(_ => console.log(`Made a cake`), 1000)
}

์ผ€์ดํฌ ๋งŒ๋“ค๊ธฐ ๊ธฐ๋Šฅ์€ ์‹œ๊ฐ„ ์ดˆ๊ณผ๋ผ๋Š” ๋ถ€์ž‘์šฉ์„ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค. ๋” ๋‚˜์•„๊ฐ€ ๋‹น์‹ ์ด ๋‹น์‹ ์˜ ์นœ๊ตฌ๊ฐ€ ์ผ€์ดํฌ์˜ ๋ง›์„ ์„ ํƒํ•˜๊ธฐ๋ฅผ ์›ํ•œ๋‹ค๊ณ  ํ•˜์ž. ๊ทธ๋Ÿฌ๊ธฐ ์œ„ํ•ด์„œ๋Š” makeCake์— ํ’๋ฏธ๋ฅผ ๋”ํ•  ์ˆ˜ ์žˆ๋‹ค.

function makeCake(flavor) {
  setTimeout(_ => console.log(`Made a ${flavor} cake!`), 1000)
}

function์„ ์‹คํ–‰ํ•  ๋•Œ ์ผ€์ดํฌ์— ์žฌ๋ฃŒ๋ฅผ ๋„ฃ์„ ์ˆ˜ ์žˆ๋‹ค

makeCake('banana')
// Made a banana cake!

์—ฌ๊ธฐ์„œ ๋ฌธ์ œ๋Š” ๊ทธ ๋ง›์„ ์•Œ๊ณ  ๋‚˜์„œ ๋ฐ”๋กœ ์ผ€์ดํฌ๋ฅผ ๋งŒ๋“ค๊ณ  ์‹ถ์ง€ ์•Š๋‹ค๋Š” ๊ฒƒ์ด๋‹ค. ์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด, ์ผ€์ดํฌ์˜ ๋ง›์„ ์ €์žฅํ•˜๋Š” prepareCake function์„ ๋งŒ๋“ค์—ˆ๋‹ค. prepareCake๋‚ด์˜ makeCake๋ฅผ ํด๋กœ์ €๋กœ ๋ฆฌํ„ดํ•œ๋‹ค. ์ด๋•Œ๋ถ€ํ„ฐ ์–ธ์ œ๋“ ์ง€ ์›ํ•˜๋ฉด ๋ฆฌํ„ด๋˜๋Š” ๊ธฐ๋Šฅ์„ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์ผ€์ดํฌ๋Š” 1์ดˆ ์•ˆ์— ๋งŒ๋“ค์–ด์งˆ ๊ฒƒ์ด๋‹ค.

function prepareCake (flavor) {
  return function () {
    setTimeout(_ => console.log(`Made a ${flavor} cake!`), 1000)
  }
}

const makeCakeLater = prepareCake('banana')

// And later in your code...
makeCakeLater()
// Made a banana cake!

#Private variables with closures

์ง€๊ธˆ๊นŒ์ง€ ์•Œ๊ณ  ์žˆ๋“ฏ์ด ํ•จ์ˆ˜์— ์ƒ์„ฑ๋˜๋Š” ๋ณ€์ˆ˜๋Š” ํ•จ์ˆ˜ ๋ฐ–์—์„œ ์ ‘์†ํ•  ์ˆ˜ ์—†๋‹ค. ์ ‘์†์ด ์•ˆ ๋˜๊ธฐ ๋•Œ๋ฌธ์— private๋ณ€์ˆ˜ ๋ผ๊ณ ๋„ ๋ถ€๋ฅธ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ํŠน๋ณ„ํ•œ ๊ฒฝ์šฐ์— private๋ณ€์ˆ˜์— ์ ‘๊ทผํ•ด์•ผํ•  ๋•Œ๊ฐ€ ์žˆ๋‹ค. ํด๋กœ์ ธ์—์„œ ์ด ๋ถ€๋ถ„์„ ์‘์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

function secret (secretCode) {
  return {
    saySecretCode () {
      console.log(secretCode)
    }
  }
}

const theSecret = secret('CSS Tricks is amazing')
theSecret.saySecretCode()
// 'CSS Tricks is amazing'

saySecretCode๋Š” ์œ„์˜ ์˜ˆ์—์„œ ์›๋ž˜์˜ ๋น„๋ฐ€ํ•จ์ˆ˜ ์™ธ๋ถ€์— ๋น„๋ฐ€์ฝ”๋“œ๋ฅผ ๋…ธ์ถœ์‹œํ‚ค๋Š” ์œ ์ผํ•œ ๊ธฐ๋Šฅ(ํด๋กœ์ €)์ด๋‹ค. ์ด๋Ÿฐ ๊ธฐ๋Šฅ์„ privileged function๋ผ๊ณ ๋„ ๋ถˆ๋ฆฐ๋‹ค.

#Debugging scopes with DevTools

์ตœ๊ทผ ์‚ฌ์šฉํ•œ ์Šค์ฝ”ํ”„์— ๋Œ€ํ•ด์„œ ํฌ๋กฌ์ด๋‚˜ ํŒŒ์ด์–ดํญ์Šค์˜ ๊ฐœ๋ฐœ์ž๋„๊ตฌ์—์„œ ๊ฐ„๋‹จํ•˜๊ฒŒ ๋””๋ฒ„๊น…์„ ํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์—๋Š” ๋‘ ๊ฐ€์ง€๊ฐ€ ์žˆ๋‹ค. ์ฒซ ๋ฒˆ์งธ ๋ฐฉ๋ฒ•์€ ์ฝ”๋“œ์— debugger ํ‚ค์›Œ๋“œ๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ์ด๋‹ค. ์ด๋กœ ์ธํ•ด ๋ธŒ๋ผ์šฐ์ €์—์„œ JavaScript ์‹คํ–‰์ด ์ผ์‹œ ์ค‘์ง€๋˜์–ด ๋””๋ฒ„๊น…์ด ๊ฐ€๋Šฅํ•˜๋‹ค.

function prepareCake (flavor) {
  // Adding debugger
  debugger
  return function () {
    setTimeout(_ => console.log(`Made a ${flavor} cake!`), 1000)
  }
}

const makeCakeLater = prepareCake('banana')

DevTools๋ฅผ ์—ด๊ณ  Chrome(๋˜๋Š” Firefox์˜ Debugger ํƒญ)์˜ Source(์†Œ์Šค) ํƒญ์œผ๋กœ ์ด๋™ํ•˜๋ฉด ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๋ณ€์ˆ˜๊ฐ€ ๋‚˜ํƒ€๋‚œ๋‹ค.

debugger ํ‚ค์›Œ๋“œ๋ฅผ ํ†ตํ•ด ํด๋กœ์ €๋กœ ๋ฐ˜ํ™˜ํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด๋ฒˆ์—๋Š” ์Šค์ฝ”ํ”„ ๋ณ€์ˆ˜๊ฐ€ ์–ด๋–ป๊ฒŒ ๋ณ€๊ฒฝ๋˜๋Š”์ง€ ํ™•์ธํ•ด๋ณด์ž!

function prepareCake (flavor) {
  return function () {
    // Adding debugger
    debugger
    setTimeout(_ => console.log(`Made a ${flavor} cake!`), 1000)
  }
}

const makeCakeLater = prepareCake('banana')

์ด ๋””๋ฒ„๊น… ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•˜๋Š” ๋‘ ๋ฒˆ์งธ ๋ฐฉ๋ฒ•์€ ๋ผ์ธ ๋ฒˆํ˜ธ๋ฅผ ํด๋ฆญํ•˜์—ฌ ์†Œ์Šค(๋˜๋Š” ๋””๋ฒ„๊ฑฐ) ํƒญ์— ์ง์ ‘ ์ฝ”๋“œ์— ์ค‘๋‹จ์ ์„ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ์ด๋‹ค.