Chapter 5: The (Not So) Secret Lifecycle of Variables - hochan222/Everything-in-JavaScript GitHub Wiki

When Can I Use a Variable?

greeting();
// Hello!

function greeting() { 
  console.log("Hello!");
}

์„ ์–ธ์€ ๋ฐ‘์—ํ–ˆ๋Š”๋ฐ greeting()์€ ์™œ ์‹คํ–‰๋ ๊นŒ...?
1์žฅ์—์„œ ์šฐ๋ฆฌ๋Š” ๋ชจ๋“  ์‹๋ณ„์ž๊ฐ€ ์ปดํŒŒ์ผ ์‹œ๊ฐ„๋™์•ˆ ํ•ด๋‹น ๋ฒ”์œ„์— ๋“ฑ๋ก๋œ๋‹ค๋Š” ์ ์„ ๋ฐฐ์› ๋‹ค. ๋˜ํ•œ, ๋ชจ๋“  ์‹๋ณ„์ž๋Š” ํ•ด๋‹น ๋ฒ”์œ„๊ฐ€ ์ž…๋ ฅ ๋  ๋•Œ๋งˆ๋‹ค ํ•ด๋‹น ๋ฒ”์œ„์˜ ์‹œ์ž‘ ๋ถ€๋ถ„์— ์ƒ์„ฑ๋œ๋‹ค. ์ด๋ฅผ ํ˜ธ์ด์ŠคํŒ…(hoisting)์ด๋ผ๊ณ  ํ•œ๋‹ค.

ํ•˜์ง€๋งŒ ํ˜ธ์ด์ŠคํŒ…๋งŒ์œผ๋กœ๋Š” ์งˆ๋ฌธ์— ๋Œ€ํ•œ ๋‹ต์„ ์ฐพ์„ ์ˆ˜ ์—†๋‹ค. ์Šค์ฝ”ํ”„์˜ ์‹œ์ž‘ ๋ถ€๋ถ„์—์„œ greeting์ด๋ผ๋Š” ์‹๋ณ„์ž๋ฅผ ๋ณผ ์ˆ˜ ์žˆ์ง€๋งŒ, ์„ ์–ธ๋˜๊ธฐ ์ „์— greeting() ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœ ํ•  ์ˆ˜์žˆ๋Š” ์ด์œ ๋Š” ๋ฌด์—‡์ธ๊ฐ€?
์ด ๋ง์€ ๋‹ค์Œ๊ณผ ๋™์ผํ•˜๋‹ค.
์Šค์ฝ”ํ”„๊ฐ€ ์‹คํ–‰๋˜๊ธฐ ์‹œ์ž‘ํ•˜๋Š” ์ˆœ๊ฐ„๋ถ€ํ„ฐ greeting ๋ณ€์ˆ˜์— ๊ฐ’(function reference)์ด ํ• ๋‹น๋˜๋Š” ๋ฐฉ๋ฒ•์€ ๋ฌด์—‡์ธ๊ฐ€?

๋‹ต์€ ํ•จ์ˆ˜ ํ˜ธ์ด์ŠคํŒ…์ด๋ผ๊ณ  ํ•˜๋Š” ๊ณต์‹ ํ•จ์ˆ˜ ์„ ์–ธ์˜ ํŠน์ˆ˜ํ•œ ํŠน์„ฑ๋•Œ๋ฌธ์ด๋‹ค. ํ•จ์ˆ˜ ์„ ์–ธ์˜ ์ด๋ฆ„ ์‹๋ณ„์ž๊ฐ€ ๋ฒ”์œ„์˜ ๋งจ ์œ„์— ๋“ฑ๋ก๋˜๋ฉด ํ•ด๋‹น ํ•จ์ˆ˜์˜ ์ฐธ์กฐ์— ๋Œ€ํ•ด ์ถ”๊ฐ€๋กœ ์ž๋™ โ€‹โ€‹์ดˆ๊ธฐํ™”๋œ๋‹ค.

Hoisting: Declaration vs. Expression

greeting();
// TypeError

var greeting = function greeting() { 
  console.log("Hello!");
};

ํ˜ธ์ด์ŠคํŠธ๋˜๋Š” ๊ฒƒ ์™ธ์—๋„ var๋กœ ์„ ์–ธ ๋œ ๋ณ€์ˆ˜๋Š” ๋ฒ”์œ„์˜ ์‹œ์ž‘ ๋ถ€๋ถ„์—์„œ ์ž๋™์œผ๋กœ undefined๋กœ ์ดˆ๊ธฐํ™”๋œ๋‹ค. ๋”ฐ๋ผ์„œ, greeting์€ ๋ฐ‘์—์„œ ํ•จ์ˆ˜๋กœ ์„ ์–ธ๋˜๊ธฐ์ „๊นŒ์ง€๋Š” ํ•จ์ˆ˜ ์ฐธ์กฐ๋กœ ์—ฐ๊ฒฐ์ด ์•ˆ๋œ๋‹ค.

Variable Hoisting

greeting = "Hello!"; 
console.log(greeting); 
// Hello!

var greeting = "Howdy!";
  1. ์‹๋ณ„์ž๊ฐ€ ์˜ฌ๋ผ์˜จ๋‹ค.
  2. undefined๋กœ ์ดˆ๊ธฐํ™”๋œ๋‹ค.
  3. ์ฝ”๋“œ๋ฅผ ์ง„ํ–‰ํ•œ๋‹ค.

Hoisting: Yet Another Metaphor

JS์—”์ง„์˜ ์‹คํ–‰๋ฐฉ์‹์„ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ถ”์ธก ํ•  ์ˆ˜ ์žˆ๋‹ค.

var greeting;           // hoisted declaration
greeting = "Hello!";    // the original line 1
console.log(greeting);  // Hello!
greeting = "Howdy!";    // `var` is gone!

ํ•œ๊ฐ€์ง€ ์˜ˆ์‹œ๋ฅผ ๋” ๋ณด์ž.


studentName = "Suzy";
greeting();
// Hello Suzy!

function greeting() {
  console.log(`Hello ${ studentName }!`);
}
var studentName;

์™€ ๊ฐ™์€ ์ฝ”๋“œ๋Š” ์•„๋ž˜์™€ ๊ฐ™์ด JS์—”์ง„์— ์˜ํ•ด ๋ณ€ํ™˜ ๋  ๊ฒƒ์ด๋‹ค.

function greeting() {
  console.log(`Hello ${ studentName }!`);
}
var studentName;

studentName = "Suzy";
greeting();
// Hello Suzy!

ํ˜ธ์ด์ŠคํŒ…์€ ๋ฒ”์œ„๊ฐ€ ์ž…๋ ฅ ๋  ๋•Œ๋งˆ๋‹ค ๋ณ€์ˆ˜์˜ ์ž๋™ ๋“ฑ๋ก์„ ์œ„ํ•ด ์ปดํŒŒ์ผ ์ž‘์—…์ค‘์— ๋Ÿฐํƒ€์ž„ ๋ช…๋ น์„ ์ƒ์„ฑํ•˜๋Š” ์ž‘์—…์œผ๋กœ ์ƒ๊ฐํ•˜์ž.

Re-declaration?

var studentName = "Frank"; 
console.log(studentName); 
// Frank

var studentName; 
console.log(studentName); 
// ???

๋ณ€์ˆ˜๊ฐ€ ๋‘๋ฒˆ ์„ ์–ธ๋˜๋ฉด ์–ด๋–ป๊ฒŒ ๋™์ž‘ํ• ๊นŒ...? ํ˜ธ์ด์ŠคํŒ… ๊ด€์ ์—์„œ ์œ„ ์ฝ”๋“œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ง„ํ–‰๋œ๋‹ค.

var studentName;
var studentName; // clearly a pointless no-op!

studentName = "Frank"; 
console.log(studentName); 
// Frank

console.log(studentName);
// Frank

๋”ฐ๋ผ์„œ ๋‘๋ฒˆ์งธ var studentName;๋Š” ๋ฌด์˜๋ฏธํ•˜๋‹ค.
(2์žฅ์„ ๋นŒ๋ฆฌ๋ฉด, ์Šค์ฝ”ํ”„ ๊ด€๋ฆฌ์ž์—๊ฒŒ studentName ์„ ์–ธ์ด ๋˜์—ˆ๋Š”์ง€ ๋ฌป๊ธฐ ๋•Œ๋ฌธ์— ์•„๋ฌด ์ž‘์—…๋„ ํ•˜์ง€ ์•Š๋Š”๋‹ค)

let studentName = "Frank"; 

console.log(studentName); 

let studentName = "Suzy";

let์€ ์žฌ์„ ์–ธ์„ ํ—ˆ์šฉํ•˜์ง€ ์•Š๋Š”๋‹ค. SyntaxError.
ES6๊ฐ€ let์„ ๋„์ž…ํ–ˆ์„ ๋•Œ โ€œ์žฌ ์„ ์–ธโ€์„ ๋ฐฉ์ง€ํ•˜๊ธฐ๋กœ ๊ฒฐ์ •ํ–ˆ๋‹ค.

Constants?

const ํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋ ค๋ฉด ๋ณ€์ˆ˜๋ฅผ ์ดˆ๊ธฐํ™”ํ•ด์•ผํ•˜๋ฏ€๋กœ ์„ ์–ธ์—์„œ ํ• ๋‹น์„ ์ƒ๋žตํ•˜๋ฉด SyntaxError๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.

const empty; // SyntaxError
const studentName = "Frank"; 
console.log(studentName);
// Frank

studentName = "Suzy"; // TypeError

SyntaxError๋Š” ํ”„๋กœ๊ทธ๋žจ ์‹คํ–‰ ์ „์— ๋ฐœ์ƒํ•˜๋Š” ์˜ค๋ฅ˜์ด๊ณ  TypeError๋Š” ํ”„๋กœ๊ทธ๋žจ ์‹คํ–‰์ค‘์— ๋ฐœ์ƒํ•˜๋Š” ์—๋Ÿฌ์ด๋‹ค. ๋”ฐ๋ผ์„œ const์—์„œ TypeError๋Š” ์ปดํŒŒ์ผ ์ค‘์— ๋ฐœ์ƒํ•˜์ง€ ์•Š๋Š”๋‹ค.

์žฌ์„ ์–ธ๋„ ์•ˆ๋œ๋‹ค.

const studentName = "Frank";

// obviously this must be an error
const studentName = "Suzy";

Loops

for (const i = 0; i < 3; i++) {
// oops, this is going to fail with
// a Type Error after the first iteration
}

Uninitialized Variables (aka, TDZ)

console.log(studentName);
// ReferenceError

let studentName = "Suzy";
studentName = "Suzy";   // let's try to initialize it!
// ReferenceError

console.log(studentName); 
let studentName;

var๋กœ๋Š” ์ž˜๋๋Š”๋ฐ let์€ ReferenceError๊ฐ€ ๋‚œ๋‹ค.

let studentName = "Suzy"; 
console.log(studentName); 
// Suzy

var๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด studentName์ด ๋งจ์œ„์—์„œ ์ž๋™ ์ดˆ๊ธฐํ™”๊ฐ€ ๋˜๋Š”๋ฐ let๊ณผ const๋Š” ๊ทธ๋ ‡์ง€ ๋ชปํ•˜๋‹ค.

์Šค์ฝ”ํ”„ ์ž…๋ ฅ๋ถ€ํ„ฐ ๋ณ€์ˆ˜ ์ž๋™ ์ดˆ๊ธฐํ™”๊ฐ€ ๋ฐœ์ƒํ•˜๋Š” ๊ธฐ๊ฐ„์„ ์ง€์นญํ•˜๊ธฐ ์œ„ํ•ด TC39์—์„œ ๋งŒ๋“  ์šฉ์–ด๋Š” TDZ (Temporal Dead Zone)์ด๋‹ค. TDZ๋Š” ๋ณ€์ˆ˜๊ฐ€ ์กด์žฌํ•˜์ง€๋งŒ ์—ฌ์ „ํžˆ ์ดˆ๊ธฐํ™”๋˜์ง€ ์•Š์•˜๊ธฐ ๋•Œ๋ฌธ์— ์–ด๋–ค ๋ฐฉ์‹์œผ๋กœ๋„ ์•ก์„ธ์Šค ํ•  ์ˆ˜ ์—†๋Š” ๊ฒƒ์ด๋‹ค.

var์€ ๊ธฐ์ˆ ์ ์œผ๋กœ TDZ๊ฐ€ ์žˆ์ง€๋งŒ ๊ธธ์ด๊ฐ€ 0์ด๋ฏ€๋กœ ํ”„๋กœ๊ทธ๋žจ์—์„œ ๊ด€์ฐฐ ํ•  ์ˆ˜ ์—†๋‹ค. let๊ณผ const์—๋งŒ ๊ด€์ฐฐ ๊ฐ€๋Šฅํ•œ TDZ๊ฐ€ ์žˆ๋‹ค.

askQuestion();
// ReferenceError

let studentName = "Suzy";

function askQuestion() {
  console.log(`${ studentName }, do you know?`);
}

์‹ค์ œ๋กœ๋Š” let๊ณผ const๊ฐ€ ํ˜ธ์ด์ŠคํŒ… ์•ˆ๋˜๋Š”๊ฒŒ์•„๋‹ˆ๊ณ  ๋˜์ง€๋งŒ ์ดˆ๊ธฐํ™”๊ฐ€ ์•ˆ๋˜๋Š”๊ฒƒ์ด๋‹ค.
๋…ผ์Ÿ์˜ ์—ฌ์ง€๋Š” ์ž๋™ ์ดˆ๊ธฐํ™”๊ฐ€ ํ˜ธ์ด์ŠคํŒ…์˜ ์ผ๋ถ€์ธ์ง€ ์—ฌ๋ถ€์ด๋‹ค.

var studentName = "Kyle"; {
  console.log(studentName);
  // ???
  // ..

  let studentName = "Suzy";
  console.log(studentName);
  // Suzy
}

๋‹ค์Œ ์ฝ”๋“œ๋Š” ์˜ค๋ฅ˜๋ฅผ ๋ฐœ์ƒ์‹œํ‚จ๋‹ค. ๋งŒ์•ฝ ํ˜ธ์ด์ŠคํŒ…์ด ์•ˆ๋œ๋‹ค๋ฉด ์ฒซ๋ฒˆ์งธ console์—์„œ Kyle์ด ์ถœ๋ ค๋ผ์•ผํ•œ๋‹ค. ๋”ฐ๋ผ์„œ ์šฐ๋ฆฌ๋Š” ํ˜ธ์ด์ŠคํŒ…์ด ๋ฐœ์ƒํ•จ์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค. ์ดˆ๊ธฐํ™”๋งŒ ์•ˆ๋์„ ๋ฟ์ด๋‹ค.