All Articles

๋ฒˆ์—ญ)Exploring ES6 - 9. Variables and scoping

๊ณต๋ถ€๋นผ๊ณ  ๋ชจ๋“  ๊ฒƒ์ด ์žฌ๋ฐŒ์–ด์ง„๋‹ค๋Š” ์‹œํ—˜๊ธฐ๊ฐ„์˜ ํŠน์„ฑ์„ ์ ๊ทน ํ™œ์šฉํ•ด์„œ ์ด๊ณณ์˜ CSS ๋„ ๊ณ ์น˜๊ณ , ๊ทธ ๊ธฐ๋…์œผ๋กœ ์ƒˆ๋กœ ํฌ์ŠคํŒ…์„ ํ•˜๊ธฐ๋กœ ํ–ˆ๋‹ค. ๋ญ”๊ฐ€ ์˜ค๋ฆฌ์ง€๋„ ํ•˜๋ฉด์„œ ์˜์–‘๊ฐ€๊ฐ€ ์žˆ๊ธฐ๊ฐ€ ํž˜๋“ค์–ด์„œ ๊ณต๋ถ€๋„ ํ•  ๊ฒธ ๋ฒˆ์—ญ ํฌ์ŠคํŒ…์„ ์‹œ๋„ ํ•ด๋ณด์•˜๋‹ค. ์˜ค๋Š˜ ๋ฒˆ์—ญํ•œ ํ…์ŠคํŠธ๋Š” ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์—ฐ๊ตฌ๊ฐ€์ด์‹  Axel Rauschmayer๋‹˜์ด ์“ด Exploring ES6๋ผ๋Š” online book ์˜ 9 ๋ฒˆ์งธ ๋‹จ์›์ด๋‹ค. ์˜ˆ~์ „์— ํ˜น์‹œ ๋ถ€๋ถ„๋ถ€๋ถ„ ๋ฒˆ์—ญํ•ด๋„ ๋˜๋ƒ๊ณ  ๋ฉ”์ผ์„ ๋“œ๋ ธ์—ˆ๋Š”๋ฐ ์•„์ง ๋‹ต์€ ์–ป์ง€ ๋ชปํ–ˆ๋‹ค.

์ถ”๊ฐ€: ์“ธ ๋•Œ๋Š” ๋ชฐ๋ž๋Š”๋ฐ ์ด๋ฏธ ์ „ํŽธ์ด ๋ฒˆ์—ญ๋˜์–ด ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค! https://github.com/ES678/Exploring-ES6




9. Variables and scoping

9.1 ๋“ค์–ด๊ฐ€๋ฉด์„œ

ES6 ๋Š” ๋ณ€์ˆ˜๋ฅผ ์„ ์–ธํ•˜๋Š” ๋‘๊ฐ€์ง€ ์ƒˆ๋กœ์šด ๋ฌธ๋ฒ•์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ์ƒˆ๋กญ๊ฒŒ ๋„์ž…๋œ let๊ณผ const๋Š” ES5 ์—์„œ ๋ณ€์ˆ˜๋ฅผ ์„ ์–ธํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ๋˜๋˜ var์„ ๊ฑฐ์˜ ์™„๋ฒฝํžˆ ๋Œ€์ฒดํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

9.1.1. let

let์€ var๊ณผ ์œ ์‚ฌํ•˜๊ฒŒ ๋™์ž‘ํ•˜์ง€๋งŒ, let์ด ์„ ์–ธํ•˜๋Š” ๋ณ€์ˆ˜๋Š” block-scoped๋กœ ํ˜„์žฌ ๋ธ”๋Ÿญ์—์„œ๋งŒ ์กด์žฌํ•ฉ๋‹ˆ๋‹ค. var์€ function-scoped์˜€์Šต๋‹ˆ๋‹ค.

๋‹ค์Œ ์ฝ”๋“œ์—์„œ let์œผ๋กœ ์„ ์–ธ๋œ ๋ณ€์ˆ˜์ธ tmp๋Š” line A ์—์„œ ์‹œ์ž‘ํ•˜๋Š” ๋ธ”๋Ÿญ์—์„œ๋งŒ ์กด์žฌํ•˜๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

function order(x, y) {
  if (x > y) {
    // (A)
    let tmp = x
    x = y
    y = tmp
  }
  console.log(tmp === x) // ReferenceError: tmp is not defined
  return [x, y]
}

9.1.2 const

const๋Š” let๊ณผ ์œ ์‚ฌํ•˜๊ฒŒ ๋™์ž‘ํ•˜์ง€๋งŒ, ๋ณ€์ˆ˜๋ฅผ ์„ ์–ธ ์ฆ‰์‹œ ๋ฐ”๋กœ ์ดˆ๊ธฐํ™”ํ•ด์ค˜์•ผ ํ•˜๊ณ  ์ดํ›„๋กœ ๊ทธ ๋‚ด์šฉ(value)์„ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

const foo;
    // SyntaxError: missing = in const declaration

const bar = 123;
bar = 456;
    // TypeError: `bar` is read-only

for-of๋Š” loop ๊ฐ€ ๋Œ ๋•Œ๋งˆ๋‹ค ๋ณ€์ˆ˜๋ฅผ ์„ ์–ธํ•˜๋ฏ€๋กœ, const ๋กœ loop ๋ณ€์ˆ˜๋ฅผ ์„ ์–ธํ•˜๋Š” ๊ฒƒ๋„ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

for (const x of ['a', 'b']) {
  console.log(x)
}
// Output:
// a
// b

9.1.3 ๋ณ€์ˆ˜๋ฅผ ์„ ์–ธํ•˜๋Š” ๋ฐฉ๋ฒ•๋“ค

์•„๋ž˜ ํ‘œ๋Š” ES6 ์—์„œ ๋ณ€์ˆ˜๋ฅผ ์„ ์–ธํ•˜๋Š” 6 ๊ฐ€์ง€ ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด ์ •๋ฆฌํ•ด ๋†“์€ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

![6 ways of declaring variables]({{ site.baseurl }}/images/var-cheatsheet.png)

9.2 let๊ณผ const๋ฅผ ํ†ตํ•œ block scoping

let๊ณผ const ๋‘˜ ๋‹ค block-scoped๋œ(๋ณ€์ˆ˜๋ฅผ ๊ฐ์‹ธ๋Š” ๊ฐ€์žฅ ์•ˆ์ชฝ์˜ ๋ธ”๋Ÿญ์—์„œ๋งŒ ์กด์žฌํ•˜๋Š”) ๋ณ€์ˆ˜๋ฅผ ์„ ์–ธํ•ฉ๋‹ˆ๋‹ค. ์•„๋ž˜์˜ ์ฝ”๋“œ์— const๋กœ ์„ ์–ธ๋œ tmp ๋ณ€์ˆ˜๋Š” if ๋ฌธ์˜ then-block ์—์„œ๋งŒ ์กด์žฌํ•ฉ๋‹ˆ๋‹ค.

function func() {
  if (true) {
    const tmp = 123
  }
  console.log(tmp) // ReferenceError: tmp is not defined
}

๋ฐ˜๋ฉด var๋กœ ์„ ์–ธ๋œ ๋ณ€์ˆ˜๋Š” function-scoped ๋˜์–ด์žˆ์Šต๋‹ˆ๋‹ค.

function func() {
  if (true) {
    var tmp = 123
  }
  console.log(tmp) // 123
}

Block scoping ์—์„œ๋Š” ํ•จ์ˆ˜ ๋‚ด์—์„œ ์ž ์‹œ ๋ณ€์ˆ˜๋ฅผ ๋ฎ๋Š” ๊ฒƒ(์›๋ฌธ: shadow)๋„ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

function func() {
  const foo = 5;
  if (ยทยทยท) {
     const foo = 10; // shadows outer `foo`
     console.log(foo); // 10
  }
  console.log(foo); // 5
}

9.3 const๋Š” ๋ถˆ๋ณ€ํ•˜๋Š”(immutable) ๋ณ€์ˆ˜๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค

let์œผ๋กœ ์„ ์–ธํ•œ ๋ณ€์ˆ˜๋Š” ๋ณ€๊ฒฝ๊ฐ€๋Šฅ(mutable)ํ•ฉ๋‹ˆ๋‹ค.

let foo = 'abc'
foo = 'def'
console.log(foo) // def

const๋กœ ์„ ์–ธ๋œ ์ƒ์ˆ˜๋Š” ๋ถˆ๋ณ€, ๋‹ค๋ฅธ ๊ฐ’์„ ํ• ๋‹นํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.
(strict ๋ชจ๋“œ์™€ ์ƒ๊ด€์—†์ด TypeError๋ฅผ ๋‚ด๋†“์Šต๋‹ˆ๋‹ค)

const foo = 'abc'
foo = 'def' // TypeError

9.3.1 ํ•จ์ •: const๋Š” ๋ณ€์ˆ˜์˜ ๊ฐ’์„ ๋ถˆ๋ณ€ํ•˜๊ฒŒ ๋งŒ๋“ค์–ด์ฃผ์ง€๋Š” ์•Š์Šต๋‹ˆ๋‹ค

const๋Š” ๋ณ€์ˆ˜๊ฐ€ ํ•ญ์ƒ ๊ฐ™์€ ๊ฐ’์„ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค๋Š” ๋œป์ผ ๋ฟ, ๊ทธ ๊ฐ’ ์ž์ฒด๊ฐ€ ๋ณ€ํ•  ์ˆ˜ ์—†๋‹ค๋Š” ๋œป์€ ์•„๋‹™๋‹ˆ๋‹ค. ์•„๋ž˜์˜ ์˜ˆ์—์„œ obj๋Š” ๋ถˆ๋ณ€์ด์ง€๋งŒ ๊ทธ๊ฒƒ์ด ๊ฐ€๋ฆฌํ‚ค๊ณ  ์žˆ๋Š” ๊ฐ’์€ ๋ณ€ํ•  ์ˆ˜ ์žˆ์–ด์„œ ์šฐ๋ฆฌ๊ฐ€ ์†์„ฑ์„ ๋”ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

const obj = {}
obj.prop = 123
console.log(obj.prop) // 123

๋ฌผ๋ก  obj์— ๋‹ค๋ฅธ ๊ฐ’์„ ํ• ๋‹นํ•˜๋Š” ๊ฒƒ์€ ๋ถˆ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

obj = {}; // TypeError

๋งŒ์•ฝ obj์˜ ๊ฐ’ ์ž์ฒด๋ฅผ ๋ถˆ๋ณ€ํ•˜๊ฒŒ ํ•˜๊ณ  ์‹ถ์„ ๋•Œ๋Š” freeze ๋“ฑ์„ ์ด์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

const obj = Object.freeze({})
obj.prop = 123 // TypeError

9.3.1.1 ํ•จ์ •: Object.freeze()๋Š” shallowํ•ฉ๋‹ˆ๋‹ค.

Object.freeze()๊ฐ€ shallow, ์ฆ‰ ๋Œ€์ƒ์˜ property๋งŒ์„ freeze ํ•  ๋ฟ object๋กœ ๋˜์–ด์žˆ๋Š” property๊นŒ์ง€ freezeํ•˜์ง€๋Š” ์•Š์Šต๋‹ˆ๋‹ค. ์•„๋ž˜ ์ฝ”๋“œ์—์„œ obj๋Š” freeze๋˜์žˆ์ง€๋งŒ,

> const obj = Object.freeze({ foo: {} });
> obj.bar = 123
TypeError: Can't add property bar, object is not extensible
> obj.foo = {}
TypeError: Cannot assign to read only property 'foo' of #<Object>

obj.foo๋Š” ๊ทธ๋ ‡์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

> obj.foo.qux = 'abc';
> obj.foo.qux
'abc'

9.3.2 Loop body ์•ˆ์—์„œ์˜ const

const ๋ณ€์ˆ˜๊ฐ€ ํ•œ ๋ฒˆ ์„ ์–ธ๋˜๊ณ ๋‚˜๋ฉด ๊ทธ ๊ฐ’(๋ฌด์—‡์„ ๊ฐ€๋ฆฌํ‚ค๊ณ  ์žˆ๋Š”์ง€)๋Š” ๋ณ€ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ๊ทธ๋ ‡๋‹ค๊ณ  ํ•ด์„œ scope ์— ๋‹ค์‹œ ๋“ค์–ด๊ฐ€ ๋ณ€์ˆ˜๋ฅผ ์ƒˆ๋กญ๊ฒŒ ์„ ์–ธํ•  ์ˆ˜ ์—†๋Š” ๊ฒƒ์€ ์•„๋‹™๋‹ˆ๋‹ค. ์•„๋ž˜ ์ฝ”๋“œ๋ฅผ ์ฐธ๊ณ ํ•ด ์ฃผ์„ธ์š”.

function logArgs(...args) {
  for (const [index, elem] of args.entries()) {
    const message = index + '. ' + elem
    console.log(message)
  }
}
logArgs('Hello', 'everyone')

// Output:
// 0. Hello
// 1. everyone

9.4 Temporal dead zone

let๊ณผ const๋กœ ์„ ์–ธ๋œ ๋ณ€์ˆ˜๋Š” temporal dead zone(TDZ)๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๋ณ€์ˆ˜์˜ scope ์— ๋“ค์–ด๊ฐ”๋”๋ผ๋„ ์„ ์–ธ๋ถ€๋ถ„์ด ์‹คํ–‰๋˜๊ธฐ ์ „์—๋Š” ์ ‘๊ทผ(get ๋˜๋Š” set)์ด ๋ถˆ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค. TDZ ๊ฐ€ ์—†๋Š” var๋กœ ์„ ์–ธ๋œ ๋ณ€์ˆ˜(์ดํ•˜ var๋ณ€์ˆ˜)์™€ TDZ ๋ฅผ ์ง€๋‹Œ let์œผ๋กœ ์„ ์–ธ๋œ ๋ณ€์ˆ˜(let๋ณ€์ˆ˜)์˜ ์ƒ์• ์ฃผ๊ธฐ๋ฅผ ๋น„๊ตํ•ด๋ด…์‹œ๋‹ค.

9.4.1 var๋กœ ์„ ์–ธ๋œ ๋ณ€์ˆ˜์˜ ์ƒ์• ์ฃผ๊ธฐ

var๋ณ€์ˆ˜์—๋Š” TDZ ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. var๋ณ€์ˆ˜์˜ ์ƒ์• ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

  1. var๋ณ€์ˆ˜์˜ scope(๋‘˜๋Ÿฌ์‹ธ๊ณ  ์žˆ๋Š” ํ•จ์ˆ˜)์— ์ง„์ž…ํ•˜๋ฉด, ๋ณ€์ˆ˜๋ฅผ ์œ„ํ•œ ์ €์žฅ์†Œ(binding)๊ฐ€ ์ƒ์„ฑ๋˜๋ฉฐ ๋ณ€์ˆ˜๋Š” undefined ๋กœ ์ฆ‰์‹œ ์ดˆ๊ธฐํ™”๋ฉ๋‹ˆ๋‹ค.
  2. ์„ ์–ธ๋ถ€๋ถ„์ด ์‹คํ–‰๋˜๋ฉด var๋ณ€์ˆ˜๋Š” initializer์˜ ๊ฐ’์„ ๊ฐ€์ง€๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ๋งŒ์•ฝ ๊ฐ’์ด ์ฃผ์–ด์ง€์ง€ ์•Š์•˜๋‹ค๋ฉด ๋ณ€์ˆ˜๋Š” ๊ณ„์†ํ•ด์„œ undefined๊ฐ’์„ ๊ฐ€์ง€๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

9.4.2 let์œผ๋กœ ์„ ์–ธ๋œ ๋ณ€์ˆ˜์˜ ์ƒ์• ์ฃผ๊ธฐ

let๋ณ€์ˆ˜๋Š” TDZ ๋ฅผ ์ง€๋‹ˆ๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. let๋ณ€์ˆ˜์˜ ์ƒ์• ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

  1. let๋ณ€์ˆ˜์˜ scope(๋‘˜๋Ÿฌ์‹ธ๊ณ  ์žˆ๋Š” ๋ธ”๋Ÿญ)์— ์ง„์ž…ํ•˜๋ฉด, ๋ณ€์ˆ˜๋ฅผ ์œ„ํ•œ ์ €์žฅ์†Œ(binding)๊ฐ€ ์ƒ์„ฑ๋˜์ง€๋งŒ ์ดˆ๊ธฐํ™”๋Š” ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
  2. ์ดˆ๊ธฐํ™”๋˜์ง€ ์•Š์€ ๋ณ€์ˆ˜์— ์ ‘๊ทผํ•˜๊ณ ์žํ•˜๋ฉด ReferenceError๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.
  3. ์„ ์–ธ๋ถ€๋ถ„์ด ์‹คํ–‰๋˜๋ฉด let๋ณ€์ˆ˜๋Š” initializer์˜ ๊ฐ’์„ ๊ฐ€์ง€๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ๋งŒ์•ฝ ๊ฐ’์ด ์ฃผ์–ด์ง€์ง€ ์•Š์•˜๋‹ค๋ฉด ๋ณ€์ˆ˜๋Š” ์ด์ œ๋ถ€ํ„ฐ undefined๊ฐ’์„ ๊ฐ€์ง€๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

const ๋ณ€์ˆ˜๋Š” let ๋ณ€์ˆ˜์™€ ์œ ์‚ฌํ•˜๊ฒŒ ๋™์ž‘ํ•˜์ง€๋งŒ initializer ๋ฅผ ๊ผญ ๊ฐ€์ง€๊ณ  ์žˆ์–ด์•ผํ•ฉ๋‹ˆ๋‹ค.

9.4.3 ์˜ˆ์‹œ

TDZ ์•ˆ์—์„œ ๋ณ€์ˆ˜์— ์ ‘๊ทผํ•˜๋ คํ•˜๋ฉด ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

let tmp = true
if (true) {
  // enter new scope, TDZ starts

  // Uninitialized binding for `tmp` is created
  console.log(tmp) // ReferenceError

  let tmp // TDZ ends, `tmp` is initialized with `undefined`
  console.log(tmp) // undefined

  tmp = 123
  console.log(tmp) // 123
}
console.log(tmp) // true

Initializer ๊ฐ€ ์žˆ์„ ๊ฒฝ์šฐ TDZ ๋Š” assignment ๊ฐ€ ์ด๋ฃจ์–ด์ง„ ํ›„์— ๋๋‚ฉ๋‹ˆ๋‹ค.

let foo = console.log(foo) // ReferenceError

์•„๋ž˜์˜ ์ฝ”๋“œ๋Š” TDZ ๊ฐ€ spatial(๊ณต๊ฐ„ ๊ธฐ๋ฐ˜)ํ•˜์ง€ ์•Š๊ณ  temporal(์‹œ๊ฐ„ ๊ธฐ๋ฐ˜)ํ•จ์„ ๋ณด์—ฌ์ค๋‹ˆ๋‹ค.

if (true) {
  // enter new scope, TDZ starts
  const func = function() {
    console.log(myVar) // OK!
  }

  // Here we are within the TDZ and
  // accessing `myVar` would cause a `ReferenceError`

  let myVar = 3 // TDZ ends
  func() // called outside TDZ
}

9.4.4 typeof๋Š” TDZ ์•ˆ์— ์žˆ๋Š” ๋ณ€์ˆ˜์— ๋Œ€ํ•ด ReferenceError๋ฅผ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

๋งŒ์•ฝ TDZ ์•ˆ์— ์žˆ๋Š” ๋ณ€์ˆ˜๋ฅผ typeof ๋ฅผ ํ†ตํ•ด ์ ‘๊ทผํ•˜๊ณ ์žํ•˜๋ฉด ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

if (true) {
  console.log(typeof foo) // ReferenceError (TDZ)
  console.log(typeof aVariableThatDoesntExist) // 'undefined'
  let foo
}

์ด์œ ๋ฅผ ์ƒ๊ฐํ•ด๋ด…์‹œ๋‹ค. foo๋Š” ์•„์ง ์„ ์–ธ๋˜์ง€ ์•Š์•˜๊ณ , ๋”ฐ๋ผ์„œ foo ๋Š” ์ดˆ๊ธฐํ™”๋˜์ง€๋„ ์•Š์•˜์Šต๋‹ˆ๋‹ค(let๋ณ€์ˆ˜๋‹ˆ๊นŒ). ํ”„๋กœ๊ทธ๋ž˜๋จธ๋Š” foo์˜ ์กด์žฌ์— ๋Œ€ํ•ด ํ˜ผ๋™์„ ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ๊ฒฝ๊ณ ๋ฅผ ์ฃผ๋Š” ๊ฒƒ์ด ๋ฐ”๋žŒ์งํ•ด๋ณด์ž…๋‹ˆ๋‹ค.

๋˜ํ•œ ์ด๋Ÿฐ ๋ฅ˜์˜ ๊ฒ€์‚ฌ๋Š” ์กฐ๊ฑด๋ถ€๋กœ ์ „์—ญ ๋ณ€์ˆ˜๋ฅผ ์„ ์–ธํ•˜๋Š” ๊ฒฝ์šฐ์—๋„ ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” ์˜ค๋กœ์ง€ ์ˆ™๋ จ๋œ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ํ”„๋กœ๊ทธ๋ž˜๋จธ๋“ค๋งŒ์ด ํ•ด์•ผํ•˜๋Š” ์ผ์ด๋ฉฐ var๋ฅผ ํ†ตํ•ด ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. typeof๋ฅผ ์ด์šฉํ•˜์ง€ ์•Š๊ณ ๋„ ์ „์—ญ ๋ณ€์ˆ˜๊ฐ€ ์กด์žฌํ•˜๋Š”์ง€๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

// With `typeof`
if (typeof someGlobal === 'undefined') {
    var someGlobal = { ยทยทยท };
}

// Without `typeof`
if (!('someGlobal' in window)) {
    window.someGlobal = { ยทยทยท };
}

๊ฐ€์ฒซ๋ฒˆ์งธ ๋ฐฉ๋ฒ•์€ global scope ์—์„œ๋งŒ ์œ ํšจํ•˜๋ฉฐ ES6 ๋ชจ๋“ˆ ์•ˆ์—์„œ๋Š” ์‚ฌ์šฉ๋  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.
(์—ญ์ž ์ฃผ: ๊ผญ es6 ์•„๋‹ˆ์–ด๋„ function(){ {์ฝ”๋“œ๋ณต๋ถ™} } ํ•˜๋Š” ๋„๊ตฌ๋“ค์—์„œ๋Š” ๋‹ค ์•ˆ๋ ๋“ฏ..)

9.4.5 TDZ ๋Š” ์™œ ์žˆ๋‚˜์š”?

  • ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์—๋Ÿฌ๋ฅผ ์žก๊ธฐ ์œ„ํ•ด์„œ: ๋ณ€์ˆ˜์˜ ์„ ์–ธ ์ „์— ์ ‘๊ทผ์ด ๊ฐ€๋Šฅํ•œ ๊ฒƒ์€ ๋ฐ”๋žŒ์งํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ด๋Ÿฐ ๊ฒฝ์šฐ๋Š” ๋ณดํ†ต ์‹ค์ˆ˜์ธ ๊ฒฝ์šฐ๊ฐ€ ๋งŽ๊ณ  ๊ฒฝ๊ณ ๋ฅผ ๋ฐ›๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.
  • const๋ฅผ ์œ„ํ•ด: const๋ฅผ ์˜ณ๊ฒŒ ๋™์ž‘ํ•˜๋„๋ก ๋งŒ๋“ค๊ธฐ๋Š” ์–ด๋ ต์Šต๋‹ˆ๋‹ค. Allen Wirfs-Brock ๋ฅผ ์ธ์šฉํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.
    โ€œTDZ ๋Š”โ€ฆconst์˜ ํ•ฉ๋ฆฌ์  ์˜๋ฏธ(rational semantics)๋ฅผ ๋ถ€์—ฌํ•ฉ๋‹ˆ๋‹ค. ์ด ์ฃผ์ œ์— ๋Œ€ํ•œ ์ƒ๋‹นํ•œ ๊ธฐ์ˆ ์  ๋…ผ์˜๊ฐ€ ์žˆ์—ˆ๊ณ  ๊ทธ ๊ฒฐ๊ณผ TDZ ๊ฐ€ ์ œ์ผ ์ข‹์€ ๋ฐฉ๋ฒ•์œผ๋กœ ์ƒ๊ฒจ๋‚ฌ์Šต๋‹ˆ๋‹ค. let ์—ญ์‹œ TDZ ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์–ด let๊ณผ const๋ฅผ ๋ฐ”๊พธ์–ด ์จ๋„ ์˜ˆ์ƒ์น˜ ๋ชปํ•˜๊ฒŒ ๋™์ž‘์ด ๋ณ€ํ•˜๋Š” ์ผ์ด ์—†์Šต๋‹ˆ๋‹ค.โ€
  • (๋ฏธ๋ž˜์— ๋‚˜์˜ฌ ์ˆ˜๋„ ์žˆ๋Š”) guard ๋ฅผ ์œ„ํ•ด: ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋Š” ์–ธ์  ๊ฐ€ guards - ๋Ÿฐํƒ€์ž„์— ๋ณ€์ˆ˜๊ฐ€ ์˜ณ์€ ๊ฐ’์„ ๊ฐ€์ง€๊ณ  ์žˆ๋Š”์ง€๋ฅผ ๊ฒ€์‚ฌํ•˜๋Š” ๋ฉ”์ปค๋‹ˆ์ฆ˜(ํƒ€์ž…์ฒดํฌ๋ฅผ ์ƒ๊ฐํ•ด๋ณด์„ธ์š”) - ๋ฅผ ๊ฐ€์ง€๊ฒŒ ๋  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ๋งŒ์•ฝ ๋ณ€์ˆ˜๊ฐ€ ์„ ์–ธ๋˜๊ธฐ๋„ ์ „์— undefined ๊ฐ’์„ ๊ฐ€์ง€๊ณ  ์žˆ์œผ๋ฉด ๊ฐ€๋“œ๊ฐ€ ๋ณด์žฅํ•ด์ฃผ๋Š” ๋‚ด์šฉ๊ณผ ์ถฉ๋Œ์ด ์ผ์–ด๋‚  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. (์—ญ์ž ์ฃผ: ์ €์ฒ˜๋Ÿผ guard ์— ๋Œ€ํ•ด ์ƒ์†Œํ•˜์‹  ๋ถ„๋“ค์€ Swift ์ชฝ์—์„œ ์ฐพ์•„๋ณด์‹œ๋ฉด ์ฐธ๊ณ ํ• ๋งŒํ•œ ๊ธ€์ด๋“ค ๋งŽ์Šต๋‹ˆ๋‹ค. ์˜ˆ )

9.4.6 ์ฝ์„ ๊ฑฐ๋ฆฌ๋“ค

9.5 loop ๋จธ๋ฆฌ(loop heads)์—์„œ์˜ let๊ณผ const๋“ค

(์—ญ์ž ์ฃผ: loop head ๋Š” for (์ดˆ๊ธฐ๋ฌธ; ์กฐ๊ฑด๋ฌธ; ์ฆ๊ฐ๋ฌธ) <-๊นŒ์ง€๋ฅผ ๋งํ•ฉ๋‹ˆ๋‹ค. โ€˜loop ์œ„โ€™๋กœ ๋ฒˆ์—ญํ•œ ๊ธ€๋„ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค)

๋‹ค์Œ loop ๋ฌธ์˜ ๋จธ๋ฆฌ์—์„œ๋Š” ๋ณ€์ˆ˜ ์„ ์–ธ์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

  • for
  • for-in
  • for-of

๋ณ€์ˆ˜ ์„ ์–ธ์„ ์œ„ํ•ด์„œ๋Š” var, let, const ์ค‘ ํ•˜๋‚˜๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ฐ๊ฐ์ด ์–ด๋–ป๊ฒŒ ๋‹ค๋ฅธ ๊ฒฐ๊ณผ๋ฅผ ๋‚ด๋†“๋Š”์ง€ ์„ค๋ช…ํ•ด๋“œ๋ฆฌ๊ฒ ์Šต๋‹ˆ๋‹ค.

9.5.1 for loop

loop ๋จธ๋ฆฌ์—์„œ var๋ฅผ ํ†ตํ•ด ๋ณ€์ˆ˜๋ฅผ ์„ ์–ธํ•˜๋ฉด binding(์ €์žฅ ๊ณต๊ฐ„) ํ•˜๋‚˜๊ฐ€ ์ƒ๊น๋‹ˆ๋‹ค.

const arr = []
for (var i = 0; i < 3; i++) {
  arr.push(() => i)
}
arr.map(x => x()) // [3,3,3]

3 ๊ฐœ์˜ arrow function ์•ˆ์— ์žˆ๋Š” 3 ๊ฐœ์˜ i๋Š” ๋ชจ๋‘ ๋™์ผํ•œ binding ์„ ๊ฐ€๋ฆฌํ‚ค๊ณ  ์žˆ๊ณ , ๋”ฐ๋ผ์„œ ๋ชจ๋‘ ๊ฐ™์€ ๊ฐ’์„ ์ถœ๋ ฅํ•ฉ๋‹ˆ๋‹ค.

๋งŒ์•ฝ let์„ ์ด์šฉํ•ด์„œ ๋ณ€์ˆ˜๋ฅผ ์„ ์–ธํ–ˆ๋‹ค๋ฉด loop ๊ฐ€ ๋Œ ๋•Œ ๋งˆ๋‹ค ์ƒˆ๋กœ์šด binding ์ด ์ƒ๊น๋‹ˆ๋‹ค.

const arr = []
for (let i = 0; i < 3; i++) {
  arr.push(() => i)
}
arr.map(x => x()) // [0,1,2]

์ด๋ฒˆ์—๋Š” ๊ฐ๊ฐ์˜ i๊ฐ€ ๊ฐ๊ฐ์˜ iteration ์˜ binding ์„ ๊ฐ€๋ฆฌํ‚ค๊ณ  ์žˆ๊ณ  ๊ทธ ๋‹น์‹œ์˜ ๊ฐ’์„ ์ง€๋‹ˆ๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ 3 ๊ฐœ์˜ ํ•จ์ˆ˜๋Š” ๋‹ค๋ฅธ ๊ฐ’๋“ค์„ ์ถœ๋ ฅํ•ฉ๋‹ˆ๋‹ค.

const๋Š” var์ฒ˜๋Ÿผ ๋™์ž‘ํ•˜์ง€๋งŒ const๋กœ ์„ ์–ธ๋œ ๋ณ€์ˆ˜์˜ ๊ฐ’์€ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

// TypeError: Assignment to constant variable
// (due to i++)
for (const i = 0; i < 3; i++) {
  console.log(i)
}

iteration ๋งˆ๋‹ค ์ƒˆ๋กœ์šด binding ์ด ์ƒ๊ธฐ๋Š” ๊ฒƒ์ด ์ด์ƒํ•ด๋ณด์ผ ์ˆ˜ ์žˆ์ง€๋งŒ loop ๋ณ€์ˆ˜๋ฅผ ์ฐธ์กฐํ•˜๋Š” ํ•จ์ˆ˜๋“ค์„ ๋งŒ๋“ค๊ธฐ ์œ„ํ•ด loop ๋ฅผ ์“ฐ๋Š” ๊ฒฝ์šฐ์—๋Š” ์•„์ฃผ ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค. ๋‹ค์Œ ์„น์…˜์—์„œ ๋” ์ž์„ธํžˆ ์„ค๋ช…๋“œ๋ฆฌ๊ฒ ์Šต๋‹ˆ๋‹ค.

9.5.2 for-of loop ๊ณผ for-in loop

for-of loop ๋‚ด์—์„œ var๋Š” binding ํ•˜๋‚˜๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค

const arr = []
for (var i of [0, 1, 2]) {
  arr.push(() => i)
}
arr.map(x => x()) // [2,2,2]

let์€ iteration ํ•œ ๋ฒˆ ๋งˆ๋‹ค binding ํ•˜๋‚˜๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค

const arr = []
for (let i of [0, 1, 2]) {
  arr.push(() => i)
}
arr.map(x => x()) // [0,1,2]

const๋Š” var์ฒ˜๋Ÿผ ๋™์ž‘ํ•˜์ง€๋งŒ const๋กœ ์„ ์–ธ๋œ ๋ณ€์ˆ˜์˜ ๊ฐ’์€ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

for-in loop ๋‚ด๋ถ€์—์„œ์˜ ๋™์ž‘์€ for-of์™€ ์œ ์‚ฌํ•ฉ๋‹ˆ๋‹ค.

(์—ญ์ž์ฃผ: ์ŠคํŽ™์— ๊ด€ํ•œ ๋ถ€๋ถ„์€ ์ƒ๋žตํ–ˆ์Šต๋‹ˆ๋‹ค. http://exploringjs.com/es6/ch_variables.html#_for-loop-per-iteration-bindings-in-the-spec)

9.5.3 iteration ๋งˆ๋‹ค binding ์ด ์ƒ๊ธฐ๋Š” ๊ฒƒ์ด ์™œ ์œ ์šฉํ•œ๊ฐ€์š”?

๋‹ค์Œ์€ ๋งํฌ 3 ๊ฐœ๋ฅผ ๋ณด์—ฌ์ฃผ๋Š” HTML ํŽ˜์ด์ง€์ž…๋‹ˆ๋‹ค.

  1. โ€œyesโ€๋ฅผ ํด๋ฆญํ•˜๋ฉด โ€œjaโ€๋กœ ๋ฒˆ์—ญ๋ฉ๋‹ˆ๋‹ค
  2. โ€œnoโ€๋ฅผ ํด๋ฆญํ•˜๋ฉด โ€œneinโ€๋กœ ๋ฒˆ์—ญ๋ฉ๋‹ˆ๋‹ค
  3. โ€œperhapsโ€๋ฅผ ํด๋ฆญํ•˜๋ฉด โ€œvielleichtโ€๋กœ ๋ฒˆ์—ญ๋ฉ๋‹ˆ๋‹ค.
 <!doctype html>๊ฐœ
<html>
<head>
    <meta charset="UTF-8">
</head>
<body>
    <div id="content"></div>
    <script>
        const entries = [
            ['yes', 'ja'],
            ['no', 'nein'],
            ['perhaps', 'vielleicht'],
        ];
        const content = document.getElementById('content');
        for (let [source, target] of entries) { // (A)
            content.insertAdjacentHTML('beforeend',
                `<div><a id="${source}" href="">${source}</a></div>`);
            document.getElementById(source).addEventListener(
                'click', (event) => {
                    event.preventDefault();
                    alert(target); // (B)
                });
        }
    </script>
</body>
</html>

line B ์— ์žˆ๋Š” target๋ณ€์ˆ˜์— ์˜ํ•ด์„œ ๋ณด์—ฌ์งˆ ๊ฒฐ๊ณผ๋ฌผ์ด ์ •ํ•ด์ง‘๋‹ˆ๋‹ค. ๋งŒ์•ฝ line A ์—์„œ let๋Œ€์‹  var๊ฐ€ ์“ฐ์˜€๋‹ค๋ฉด, ๋ฃจํ”„ ์ „์ฒด์— ๋Œ€ํ•ด์„œ binding ํ•˜๋‚˜๊ฐ€ ์ƒ๊ธฐ๊ณ  ๊ทธ ๊ฐ’์€ ๊ฒฐ๊ตญ ๋งˆ์ง€๋ง‰์œผ๋กœ ์ €์žฅ๋œ โ€˜vielleichtโ€™๊ฐ€ ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ์šฐ๋ฆฌ๊ฐ€ ์–ด๋Š ๋งํฌ๋ฅผ ๋ˆ„๋ฅด๋˜ โ€˜vielleichtโ€™์ด ์ถœ๋ ฅ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

ํ•˜์ง€๋งŒ ๊ณ ๋ง™๊ฒŒ๋„ let์„ ํ†ตํ•ด์„œ iteration ๋งˆ๋‹ค binding ์ด ์ƒ๊ธฐ๊ณ , ๋ฒˆ์—ญ ๊ฒฐ๊ณผ๊ฐ€ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์ถœ๋ ฅ๋ฉ๋‹ˆ๋‹ค.

9.6 ํŒจ๋Ÿฌ๋ฏธํ„ฐ

9.6.1 ํŒจ๋Ÿฌ๋ฏธํ„ฐ vs. ์ง€์—ญ ๋ณ€์ˆ˜

๋งŒ์•ฝ ํŒจ๋Ÿฌ๋ฏธํ„ฐ์™€ ๊ฐ™์€ ์ด๋ฆ„์„ ๊ฐ€์ง„ ๋ณ€์ˆ˜๋ฅผ let์œผ๋กœ ์„ ์–ธํ•˜๋ฉด static(load-time)์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค

function func(arg) {
  let arg // static error: duplicate declaration of `arg`
}

๊ฐ™์€ ์ผ์„ ๋ธ”๋Ÿญ ์•ˆ์—์„œํ•˜๋ฉด ํŒจ๋Ÿฌ๋ฏธํ„ฐ๋ฅผ ์ž ์‹œ ๊ฐ€๋ฆฝ๋‹ˆ๋‹ค(shadow)

function func(arg) {
  {
    let arg // shadows parameter `arg`
  }
}

๋ฐ˜๋ฉด ํŒจ๋Ÿฌ๋ฏธํ„ฐ์™€ ๊ฐ™์€ ์ด๋ฆ„์„ ๊ฐ€์ง„ ๋ณ€์ˆ˜๋ฅผ var์œผ๋กœ ์„ ์–ธํ•  ๊ฒฝ์šฐ, ์•„๋ฌด ์ผ๋„ ์ผ์–ด๋‚˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ด๋Š” ๊ฐ™์€ scope ์—์„œ var๋ณ€์ˆ˜๋ฅผ ์ƒˆ๋กœ ์„ ์–ธํ•˜๋ฉด ์•„๋ฌด ์ผ๋„ ์ผ์–ด๋‚˜์ง€ ์•Š๋Š” ๊ฒƒ๊ณผ ๊ฐ™์€ ์›๋ฆฌ์ž…๋‹ˆ๋‹ค.

function func(arg) {
  var arg // does nothing
}

function func(arg) {
  {
    // We are still in same `var` scope as `arg`
    var arg // does nothing
  }
}

9.6.2 ํŒจ๋Ÿฌ๋ฏธํ„ฐ ๊ธฐ๋ณธ๊ฐ’๊ณผ TDZ

๋งŒ์•ฝ ํŒจ๋Ÿฌ๋ฏธํ„ฐ๊ฐ€ ๊ธฐ๋ณธ ๊ฐ’๋“ค์„ ๊ฐ€์ง€๊ณ  ์žˆ์œผ๋ฉด ์ด๋“ค์€ let ์„ ์–ธ์˜ ์—ฐ์†์ฒ˜๋Ÿผ ์ฒ˜๋ฆฌ๋˜๊ณ  TDZ ๋ฅผ ์ง€๋‹™๋‹ˆ๋‹ค.

// OK: `y` accesses `x` after it has been declared
function foo(x = 1, y = x) {
  return [x, y]
}
foo() // [1,1]

// Exception: `x` tries to access `y` within TDZ
function bar(x = y, y = 2) {
  return [x, y]
}
bar() // ReferenceError

9.6.3 ํŒจ๋Ÿฌ๋ฏธํ„ฐ ๊ธฐ๋ณธ๊ฐ’์€ ํ•จ์ˆ˜ body ์˜ scope ๋ฅผ ๋”ฐ๋ฅด์ง€ ์•Š์Šต๋‹ˆ๋‹ค

ํŒจ๋Ÿฌ๋ฏธํ„ฐ ๊ธฐ๋ณธ๊ฐ’์˜ scope ๋Š” ํ•จ์ˆ˜ body ์™€ ๋ณ„๋„์˜ scope ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค(๊ธฐ๋ณธ๊ฐ’์˜ scope ๊ฐ€ body ๋ฅผ ๊ฐ์Œ‰๋‹ˆ๋‹ค). ๋”ฐ๋ผ์„œ ํ•จ์ˆ˜ ํŒจ๋Ÿฌ๋ฏธํ„ฐ ๊ธฐ๋ณธ๊ฐ’ ๋‚ด์˜ method ๋‚˜ ํ•จ์ˆ˜๋Š” body ์˜ ์ง€์—ญ ๋ณ€์ˆ˜๋ฅผ ๋ณผ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

const foo = 'outer'
function bar(func = x => foo) {
  const foo = 'inner'
  console.log(func()) // outer
}
bar()

9.7 ์ „์—ญ ๊ฐ์ฒด

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์˜ ์ „์—ญ๊ฐ์ฒด (๋ธŒ๋ผ์šฐ์ €์—์„œ์˜ window, Node.js ์—์„œ๋Š” global) ๋Š” ๊ธฐ๋Šฅ์ด๋ผ๊ธฐ ๋ณด๋‹ค๋Š” ๋ฒ„๊ทธ์— ๊ฐ€๊น์Šต๋‹ˆ๋‹ค(!), ํŠนํžˆ ์„ฑ๋Šฅ ์ธก๋ฉด์—์„œ๋Š” ๋”์šฑ ๊ทธ๋ ‡์Šต๋‹ˆ๋‹ค. ๋•Œ๋ฌธ์— ES6 ์—์„œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๊ตฌ๋ถ„์ด ๋„์ž…๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

  • Global object ์˜ ๋ชจ๋“  property ๋Š” global variable ์ž…๋‹ˆ๋‹ค. Global scope ์—์„œ ๋‹ค์Œ์„ ์ด์šฉํ•œ ์„ ์–ธ์ด ๊ทธ๋Ÿฌํ•œ property ๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค.
    • var๋ฅผ ์ด์šฉํ•œ ์„ ์–ธ
    • ํ•จ์ˆ˜ ์„ ์–ธ
  • ํ•˜์ง€๋งŒ ์ด์ œ Global object ์˜ property ๊ฐ€ ์•„๋‹Œ global variable ๋“ค์ด ์กด์žฌํ•ฉ๋‹ˆ๋‹ค. Global scope ์—์„œ ๋‹ค์Œ์„ ์ด์šฉํ•œ ์„ ์–ธ์ด ๊ทธ๋Ÿฌํ•œ variable ์„ ๋งŒ๋“ญ๋‹ˆ๋‹ค.
    • let์„ ์ด์šฉํ•œ ์„ ์–ธ
    • const๋ฅผ ์ด์šฉํ•œ ์„ ์–ธ
    • Class ์„ ์–ธ

(์—ญ์ž ์ฃผ: ์ดํ•ด๊ฐ€ ์ž˜ ์•ˆ๋˜์„œ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋Š๋‚Œ์ผ๊นŒ?ํ•˜๊ณ  ์ฝ”๋“œ๋ฅผ ์งœ๋ดค๋Š”๋ฐ babel ์—์„œ let ์ด var ๋กœ ๋ฐ”๋กœ ๋ฐ”๋€Œ๋Š” ๋ฐ”๋žŒ์— ์‹คํ—˜์„ ๋ชปํ–ˆ์Šต๋‹ˆ๋‹ค)

var a = 1
let b = 1
console.log(window.a)
console.log(window.b)

9.8 ํ•จ์ˆ˜ ์„ ์–ธ๊ณผ ํด๋ž˜์Šค ์„ ์–ธ

ํ•จ์ˆ˜ ์„ ์–ธ์€โ€ฆ

  • block-scoped ์ž…๋‹ˆ๋‹ค, ๋งˆ์น˜ let ์ฒ˜๋Ÿผ
  • (Global scope ์—์„œ) global๊ฐ์ฒด์˜ property ๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค. ๋งˆ์น˜ var ์ฒ˜๋Ÿผ
  • hoist๋ฉ๋‹ˆ๋‹ค. ํ•ด๋‹น scope(์—ฌ๊ธฐ์„œ๋Š” block ๋‹จ์œ„) ์–ด๋””์„œ ํ•จ์ˆ˜๊ฐ€ ์„ ์–ธ๋˜์—ˆ๋Š”์ง€์™€ ์ƒ๊ด€์—†์ด scope ์˜ ์‹œ์ž‘๊ณผ ํ•จ๊ป˜ ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค.

๋‹ค์Œ ์ฝ”๋“œ๋Š” ํ•จ์ˆ˜ ์„ ์–ธ์ด hoist๋จ์„ ๋ณด์—ฌ์ค๋‹ˆ๋‹ค.

{
  // Enter a new scope

  console.log(foo()) // OK, due to hoisting
  function foo() {
    return 'hello'
  }
}

ํด๋ž˜์Šค ์„ ์–ธ์€โ€ฆ

  • block-scoped ์ž…๋‹ˆ๋‹ค.
  • global ๊ฐ์ฒด์— property ๋ฅผ ๋งŒ๋“ค์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
  • hoist๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

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

{
  // Enter a new scope

  const identity = x => x

  // Here we are in the temporal dead zone of `MyClass`
  const inst = new MyClass() // ReferenceError

  // Note the expression in the `extends` clause
  class MyClass extends identity(Object) {}
}

9.9 ์ฝ”๋”ฉ ์Šคํƒ€์ผ: const vs. let vs. var

ํ•ญ์ƒ let๊ณผ const ์ค‘ ํ•˜๋‚˜๋ฅผ ์ด์šฉํ•˜๋„๋ก ํ•˜์„ธ์š”.

1) ์ผ๋‹จ const๋ฅผ ๊ณ ๋ คํ•˜์„ธ์š”. ๊ฐ’์ด ์ ˆ๋Œ€ ๋ณ€ํ•˜์ง€ ์•Š์„ ๊ฒฝ์šฐ - ํ•ด๋‹น ๋ณ€์ˆ˜๊ฐ€ ์ ˆ๋Œ€ assignment ์˜ ์™ผ์ชฝ์— ์žˆ๊ฑฐ๋‚˜ ++, โ€” ๋˜์ง€ ์•Š์„ ๊ฒฝ์šฐ - ์— const๋ฅผ ์ด์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. const ๋ณ€์ˆ˜๊ฐ€ ๊ฐ€๋ฆฌํ‚ค๊ณ  ์žˆ๋Š” ๊ฐ์ฒด์˜ ์ˆ˜์ •์€ ํ—ˆ์šฉ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.

const foo = {}
foo.prop = 123 // OK

์‹ฌ์ง€์–ด const๋ฅผ for-of์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. Iteration ๋งˆ๋‹ค (๋ถˆ๋ณ€ํ•˜๋Š”)binding ์ด ์ƒ๊ธฐ๊ธฐ ๋•Œ๋ฌธ์ด์ง€์š”.

for (const x of ['a', 'b']) {
  console.log(x)
}
// Output:
// a
// b

for ๋ฌธ ์•ˆ์—์„œ x ๋Š” ์ˆ˜์ •๋  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

2) ์•„๋‹ˆ๋ผ๋ฉด, let์„ ์‚ฌ์šฉํ•˜์„ธ์š” - ๋ณ€์ˆ˜์˜ ์ดˆ๊ธฐ๊ฐ’์ด ๋‚˜์ค‘์— ๋ฐ”๋€” ๊ฒฝ์šฐ์—

let counter = 0 // initial value
counter++ // change

let obj = {} // initial value
obj = { foo: 123 } // change

3) var๋Š” ์“ฐ์ง€ ๋งˆ์„ธ์š”

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

let์ด๋‚˜ const๋Š” ํ•  ์ˆ˜ ์—†๊ณ , var๋Š” ํ•  ์ˆ˜ ์žˆ๋Š” ์ผ์ด ์žˆ์Šต๋‹ˆ๋‹ค: (global scope ์—์„œ) var๋กœ ์„ ์–ธ๋œ ๋ณ€์ˆ˜๋Š” global๊ฐ์ฒด์˜ property ๊ฐ€ ๋ฉ๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ๋ณดํ†ต ์ด๋Š” ์ข‹์€ ์ผ์ด ์•„๋‹™๋‹ˆ๋‹ค. ํ•„์š”ํ•œ ๊ฒฝ์šฐ window๋‚˜ global์— property ๋ฅผ assign ํ•ด์„œ๋„ ๊ฐ™์€ ์ผ์„ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

9.9.1 ๋‹ค๋ฅธ ์ ‘๊ทผ

์œ„์˜ ๊ทœ์น™์˜ ๋Œ€์•ˆ์œผ๋กœ const๋ฅผ completely immutable ํ•œ ๊ฒฝ์šฐ์—๋งŒ(primitive value ๋‚˜ frozen object) ์ด์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์ด ์žˆ์Šต๋‹ˆ๋‹ค. ์ด์ œ ์šฐ๋ฆฌ๋Š” ๋‘๊ฐ€์ง€ ์˜ต์…˜์„ ๊ฐ€์ง€๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

  1. ์ผ๋‹จ const(์ถ”์ฒœ): const๋Š” immutable ํ•œ binding์„ ๋œปํ•ฉ๋‹ˆ๋‹ค
  2. ์ผ๋‹จ let(๋Œ€์•ˆ): const๋Š” immutable ํ•œ value๋ฅผ ๋œปํ•ฉ๋‹ˆ๋‹ค

๋‘˜ ๊ฐ„์˜ ์šฐ์—ด์„ ๊ฐ€๋ฆฌ๊ธฐ๋Š” ํž˜๋“ญ๋‹ˆ๋‹ค. ๋‹ค๋งŒ ์ €๋Š” 1 ๋ฒˆ์„ ์•„์ฃผ ์•ฝ๊ฐ„ ์„ ํ˜ธํ•ฉ๋‹ˆ๋‹ค.




๋ฒˆ์—ญ ํ›„๊ธฐ

  1. const ์ชฝ ๋ฒˆ์—ญ์ด ์•ฝ๊ฐ„ ์ด์ƒํ•œ๋ฐ ์˜ˆ์ œ์ฝ”๋“œ๊ฐ€ ์›Œ๋‚™ ๋ช…๋ฃŒํ•ด์„œ ์ดํ•ด์—๋Š” ํฐ ์ง€์žฅ์ด ์—†์œผ๋ฆฌ๋ผ ๋ฏฟ๋Š”๋‹ค.
  2. ์™œ JS ๊ฐ€ ์š•๋จน๋Š”์ง€ ์•Œ๊ฒ ๋‹ค. ๋ง์ด TDZ ์ง€ ์‚ฌ์‹ค ๋‹ค๋ฅธ ์–ธ์–ด์—์„œ๋Š” ๋„ˆ๋ฌด๋‚˜ ์ž์—ฐ์Šค๋Ÿฌ์šด ๊ฒƒ ์•„๋‹Œ๊ฐ€โ€ฆ
  3. ๋ฒˆ์—ญ์ด ๊ฐ•๋ ฅํ•œ ํ•™์Šต ๋ฐฉ๋ฒ•์ด๊ธด ํ•œ๋ฐ, ๊ฐ€์žฅ ํšจ์œจ์ ์ธ์ง€๋Š” ์˜๋ฌธ์ด ๋‚จ๋Š”๋‹ค.

Published Jun 3, 2016

If I keep marking the dots, someday they will ๐Ÿ”—๐Ÿ”—