λ³Έλ¬Έ λ°”λ‘œκ°€κΈ°

JavaScript

λ³€μˆ˜μ˜ ν˜Έμ΄μŠ€νŒ…, TDZ의 κ°œλ… λ°”λ‘œμ•ŒκΈ°

ν˜Έμ΄μŠ€νŒ… (Hoisting) μ΄λž€ ?

JavaScriptμ—μ„œ ν˜Έμ΄μŠ€νŒ…(hoisting)μ΄λž€, 인터프리터가 λ³€μˆ˜μ™€ ν•¨μˆ˜μ˜ λ©”λͺ¨λ¦¬ 곡간을 μ„ μ–Έ 전에 미리 ν• λ‹Ήν•˜λŠ” 것을 μ˜λ―Έν•©λ‹ˆλ‹€.
-MDN-

 

ν•¨μˆ˜ μ•ˆμ— μžˆλŠ” 선언듀을 λͺ¨λ‘ λŒμ–΄μ˜¬λ €μ„œ ν•΄λ‹Ή ν•¨μˆ˜ 유효 λ²”μœ„(μ‹€ν–‰ μ»¨ν…μŠ€νŠΈ)의 μ΅œμƒλ‹¨μ— μ„ μ–Έν•˜λŠ” 것.

 

ν˜Έμ΄μŠ€νŒ…μ˜ λŒ€μƒ

 

μžλ°”μŠ€ν¬λ¦½νŠΈμ—μ„œλŠ” λͺ¨λ“  선언을 ν˜Έμ΄μŠ€νŒ…ν•œλ‹€. 

보톡 ν˜Έμ΄μŠ€νŒ…μ€ var ν‚€μ›Œλ“œλ‘œ μ„ μ–Έλœ λ³€μˆ˜μ—μ„œλ§Œ μΌμ–΄λ‚œλ‹€κ³  μƒκ°ν•˜μ§€λ§Œ let, const μ—μ„œλ„ ν˜Έμ΄μŠ€νŒ…μ΄ μΌμ–΄λ‚œλ‹€.

 

λ³€μˆ˜μ˜ 생성 단계λ₯Ό μ•Œμ•„λ³΄λ©΄μ„œ μ΄ν•΄ν•΄λ³΄μž 

 

λ³€μˆ˜λŠ” 3개의 단계λ₯Ό 거쳐 생성이 λœλ‹€.

1. 선언단계

μžλ°”μŠ€ν¬λ¦½νŠΈμ—μ„œ λ³€μˆ˜μ˜ 선언은 varconstlet ν‚€μ›Œλ“œλ‘œ ν•  수 있으며, ES6μ—μ„œ const와 let이 μΆ”κ°€λ˜μ—ˆλ‹€.

 

μ„ μ–Έλ‹¨κ³„μ—μ„œλŠ” λ³€μˆ˜λ₯Ό μ‹€ν–‰ μ»¨ν…μŠ€νŠΈμ˜ λ³€μˆ˜ 객체에 λ“±λ‘ν•˜κ³  μžλ°”μŠ€ν¬λ¦½νŠΈ 엔진에 λ³€μˆ˜μ˜ 쑴재λ₯Ό μ•Œλ¦°λ‹€.

이 λ³€μˆ˜ κ°μ²΄λŠ” μŠ€μ½”ν”„κ°€ μ°Έμ‘°ν•˜λŠ” λŒ€μƒμ΄ λœλ‹€.

2. μ΄ˆκΈ°ν™” 단계 

값을 μ €μž₯ν•˜κΈ° μœ„ν•œ λ©”λͺ¨λ¦¬ 곡간을 ν™•λ³΄ν•˜κ³  이 λ‹¨κ³„μ—μ„œ λ³€μˆ˜μ— undefinedλ₯Ό ν• λ‹Ήν•΄ μ΄ˆκΈ°ν™”ν•œλ‹€.

μ΄ˆκΈ°ν™” λ‹¨κ³„λŠ” μ–΄λŠ μ„ μ–Έ ν‚€μ›Œλ“œλ₯Ό μ‚¬μš©ν•˜λŠλƒμ— 따라 λ‹€λ₯΄κ²Œ λ‚˜νƒ€λ‚œλ‹€.

 

var ν‚€μ›Œλ“œλ₯Ό μ‚¬μš©ν•œ μ„ μ–Έ λ°©μ‹μ˜ 경우,

 

var ν‚€μ›Œλ“œλ‘œ μ„ μ–Έλœ λ³€μˆ˜λŠ” μ„ μ–Έ 단계와 μ΄ˆκΈ°ν™” 단계가 ν•œκΊΌλ²ˆμ— μΌμ–΄λ‚œλ‹€.

μ΄ˆκΈ°ν™” λ‹¨κ³„μ—μ„œ undefined둜 μ΄ˆκΈ°ν™”λ˜κΈ° λ•Œλ¬Έμ— λ³€μˆ˜λ₯Ό μ„ μ–Έν•˜κΈ° 전에 λ³€μˆ˜μ— 접근해도 μ—λŸ¬κ°€ μΌμ–΄λ‚˜μ§€ μ•ŠλŠ”λ‹€.

접근이 κ°€λŠ₯ν•΄μ§„ var ν‚€μ›Œλ“œλ‘œ μ„ μ–Έν•œ λ³€μˆ˜λŠ” μ‹€ν–‰ μ»¨ν…μŠ€νŠΈμ˜ μ΅œμƒμœ„λ‘œ μ΄λ™ν•˜κ²Œ λœλ‹€.

 

μ½”λ“œλ₯Ό 톡해 μ•Œμ•„λ³΄μž. 

 

console.log(age)  // undefined

var age = 27

console.log(age)  // 27

 

μœ„ μ½”λ“œμ—μ„œ 확인 ν•  수 μžˆλ“―μ΄, var ν‚€μ›Œλ“œλ‘œ μ„ μ–Έν•œ λ³€μˆ˜λŠ” μ„ μ–Έ 단계와 μ΄ˆκΈ°ν™” 단계가 ν•œλ²ˆμ— μΌμ–΄λ‚˜κΈ° λ•Œλ¬Έμ— 

ageλ₯Ό console.log둜 확인해보면 undefined둜 λ‚˜μ˜€κ²Œ 되고 이후 할당단계λ₯Ό 거쳐 27μ΄λΌλŠ” 값이 찍히게 λœλ‹€. 

 

μœ„μ˜ μ½”λ“œλŠ” μ•„λž˜μ™€ 같은 의미λ₯Ό κ°€μ§„λ‹€. 

 

var age

console.log(age) // undefined

age = 27

console.log(age)  // 27

 

var ν‚€μ›Œλ“œλ‘œ μ„ μ–Έν•œ λ³€μˆ˜κ°€ ν˜Έμ΄μŠ€νŒ…μ΄ λ˜μ–΄ μ‹€ν–‰ μ»¨ν…μŠ€νŠΈμ˜ μ΅œμƒλ‹¨μœΌλ‘œ μ΄λ™ν–ˆκ³ , 이 λ•Œ μ„ μ–Έκ³Ό μ΄ˆκΈ°ν™”κ°€ λ™μ‹œμ— 일어났기 λ•Œλ¬Έμ— 

undefined λΌλŠ” 값이 λ‚˜μ˜€κ²Œ λ˜λŠ” 것이닀.

 

반면,

let, const ν‚€μ›Œλ“œλ‘œ μ„ μ–Έλœ λ³€μˆ˜λŠ” var ν‚€μ›Œλ“œλ‘œ μ„ μ–Έλœ λ³€μˆ˜μ™€ 달리 μ„ μ–Έ 단계와 μ΄ˆκΈ°ν™” 단계가 λΆ„λ¦¬λ˜μ–΄μ„œ 이루어진닀.

μ΄ˆκΈ°ν™” 이전에 λ³€μˆ˜μ— μ ‘κ·Όν•˜λ €κ³  ν•˜λ©΄ μ°Έμ‘° μ—λŸ¬κ°€ λ°œμƒν•œλ‹€.

μ΄λŠ” λ³€μˆ˜λ₯Ό μœ„ν•œ λ©”λͺ¨λ¦¬ 곡간이 아직 ν™•λ³΄λ˜μ§€ μ•Šμ•˜κΈ° λ•Œλ¬Έμ΄λ‹€.

 

μŠ€μ½”ν”„μ˜ μ‹œμž‘ 지점뢀터 μ΄ˆκΈ°ν™” μ‹œμž‘ μ§€μ κΉŒμ§€μ˜ ꡬ간을 'μΌμ‹œμ  μ‚¬κ°μ§€λŒ€ TDZ(Temporal Dead Zone)' 라고 λΆ€λ₯Έλ‹€.

 

μ½”λ“œλ₯Ό 톡해 μ•Œμ•„λ³΄μž.

 

const λ³€μˆ˜

 

age; // ReferenceError
const age = 27;

 

const λ³€μˆ˜λŠ” μ΄ˆκΈ°ν™” 단계 μ΄μ „κΉŒμ§€ TDZ에 μžˆλ‹€.

 

let λ³€μˆ˜ 

 

let ν‚€μ›Œλ“œλ‘œ μ„ μ–Έν•œ λ³€μˆ˜λ„ const와 λ§ˆμ°¬κ°€μ§€λ‘œ μ΄ˆκΈ°ν™” 단계 μ΄μ „κΉŒμ§€ TDZ에 μžˆλ‹€.

 

age; // ReferenceError
console.log(age)

 

3. ν• λ‹Ή 단계

λ³€μˆ˜μ— 값을 ν• λ‹Ή ν•  λ•Œμ—λŠ” ν• λ‹Ή μ—°μ‚°μž(=)λ₯Ό μ‚¬μš©ν•΄μ„œ μ΄λ£¨μ–΄μ§€λ©° λͺ¨λ“  μ„ μ–Έ ν‚€μ›Œλ“œμ˜ 할당은 λŸ°νƒ€μž„ κ³Όμ •μ—μ„œ 이루어진닀.

 

var ν‚€μ›Œλ“œ λ³€μˆ˜λŠ” μ‹€ν–‰ μ»¨ν…μŠ€νŠΈμ˜ (μ‹€ν–‰ 단계)μ—μ„œ μ„ μ–Έκ³Ό μ΄ˆκΈ°ν™” 단계가 이루어지고, λŸ°νƒ€μž„ κ³Όμ •μ—μ„œ 할당이 이루어진닀.

 

let, const ν‚€μ›Œλ“œ λ³€μˆ˜λŠ” μ‹€ν–‰ μ»¨ν…μŠ€νŠΈμ˜ (μ‹€ν–‰ 단계)μ—μ„œ μ„ μ–Έ λ‹¨κ³„λ§Œ 이루어지고, λŸ°νƒ€μž„ κ³Όμ •μ—μ„œ μ΄ˆκΈ°ν™” 단계λ₯Ό 거쳐 λ©”λͺ¨λ¦¬ 곡간을

ν™•λ³΄ν•˜μ—¬ ν• λ‹Ή ν•  κ°’(undefined)을 μ €μž₯ν•œλ‹€. 

 

이후 ν• λ‹Ή λ‹¨κ³„μ—μ„œ undefined 으둜 μ΄ˆκΈ°ν™” λ˜μ–΄μžˆλŠ” 값을 ν• λ‹Ήλœ κ°’μœΌλ‘œ ꡐ체해쀀닀. 

 

ν•¨μˆ˜ ν˜Έμ΄μŠ€νŒ…

 

λ³€μˆ˜μ˜ ν˜Έμ΄μŠ€νŒ…μ— λŒ€ν•΄ μ•Œμ•„λ³΄μ•˜λ‹€. 이제 ν•¨μˆ˜μ˜ ν˜Έμ΄μŠ€νŒ…μ— λŒ€ν•΄ μ•Œμ•„λ³΄μž

 

ν•¨μˆ˜μ„ μ–Έλ¬ΈμœΌλ‘œ ν•¨μˆ˜λ₯Ό μ •μ˜ν•œ 경우

 

getAge(27); // μ •μƒλ™μž‘

function getAge(age) {
  console.log(age) //27
}

getAge(27); // μ •μƒλ™μž‘

 

ν•¨μˆ˜μ„ μ–Έλ¬Έμ€ TDZ에 영ν–₯을 λ°›μ§€ μ•ŠλŠ”λ‹€. ν˜„μž¬ μŠ€μ½”ν”„μ—μ„œ ν˜Έμ΄μŠ€νŒ… λœλ‹€.

 

ν•¨μˆ˜ ν‘œν˜„μ‹, ν™”μ‚΄ν‘œ ν•¨μˆ˜λ‘œ ν•¨μˆ˜λ₯Ό μ •μ˜ν•œ 경우 

 

getAge(27) 

var getAge = (age) => {  // TypeError: getAge is not a function
  console.log(age)
}

var getAge = function (age) { // TypeError: getAge is not a function
  console.log(age)
}

getAge(27)

 

반면 ν•¨μˆ˜ν‘œν˜„μ‹κ³Ό ν™”μ‚΄ν‘œ ν•¨μˆ˜λ‘œ ν•¨μˆ˜λ₯Ό μ •μ˜ν•˜κΈ° 이전에 ν•¨μˆ˜λ₯Ό ν˜ΈμΆœν•œ κ²½μš°μ—λŠ” μ—λŸ¬κ°€ λ°œμƒν•œλ‹€. 

ν˜Έμ΄μŠ€νŒ…μ΄ μΌμ–΄λ‚˜μ§€λ§Œ var둜 μ„ μ–Έν–ˆκΈ° λ•Œλ¬Έμ— getAgeμ—λŠ” undefinedκ°€ μ΄ˆκΈ°ν™” λ˜μ–΄ μžˆλŠ” 것이닀 

μœ„ ν•¨μˆ˜λ₯Ό let, const 둜 μ„ μ–Έν–ˆμ„ κ²½μš°μ—λŠ” ν•¨μˆ˜λ₯Ό μ •μ˜ν•˜κΈ° 전에 ν˜ΈμΆœν–ˆλ‹€λŠ” μ—λŸ¬κ°€ λ°œμƒν•˜κ²Œ λœλ‹€ !

 

 

var, let, const의 차이

μœ„μ—μ„œ ν™•μΈν–ˆλ“―μ΄ var ν‚€μ›Œλ“œλ‘œ ν•¨μˆ˜λ₯Ό μ„ μ–Έν•˜λŠ” κ²½μš°μ—λŠ” 문제점이 λ§Žλ‹€.

  • λ³€μˆ˜ 쀑볡 μ„ μ–Έ κ°€λŠ₯ν•˜λ‹€.
  • ν•¨μˆ˜ 레벨 μŠ€μ½”ν”„μ΄κΈ° λ•Œλ¬Έμ— ν•¨μˆ˜κ°€ μ•„λ‹Œ κ³³μ—μ„œ μ„ μ–Έν•œ λ³€μˆ˜λŠ” λͺ¨λ‘ μ „μ—­ λ³€μˆ˜λ‘œ μ·¨κΈ‰ν•œλ‹€.
  • λ³€μˆ˜μ˜ ν• λ‹Ή 단계λ₯Ό 거치기 μ΄μ „μ—λŠ” 항상 undefinedλ₯Ό κ°€μ§„λ‹€.

μ΄λŸ¬ν•œ var의 λ¬Έμ œμ μ„ ν•΄κ²°ν•˜κΈ°μœ„ν•΄ es6μ—μ„œ letκ³Ό constκ°€ νƒ„μƒν–ˆλ‹€. 

 

λ³€μˆ˜μ˜ 쀑볡 μ„ μ–Έ μ œν•œ

let ν‚€μ›Œλ“œμ™€ const ν‚€μ›Œλ“œλŠ” 같은 μŠ€μ½”ν”„ λ‚΄μ—μ„œ 쀑볡 선언을 ν—ˆμš©ν•˜μ§€ μ•ŠλŠ”λ‹€.  쀑볡 μ„ μ–Έν•˜λ©΄ λ¬Έλ²•μ—λŸ¬SyntaxErrorκ°€ λ°œμƒν•œλ‹€.

 

 

function getAge() {
  let age = 27;
  let age = 26;
  // 쀑볡 μ„ μ–ΈμœΌλ‘œ 인해 μ—λŸ¬ λ°œμƒ
  return age;
}

 

 

 

letκ³Ό const의 차이점이라면 

constλŠ” λ³€μˆ˜μ˜ μ„ μ–Έκ³Όν•¨κ»˜ μ΄ˆκΈ°ν™”λ₯Ό ν•˜μ§€ μ•ŠμœΌλ©΄ μ—λŸ¬κ°€ λ°œμƒν•œλ‹€ .

 

let age // undefined
console.log(age)

const age // Error
console.log(age)

const age = 27 
console.log(age) // 27

 

 

블둝 레벨 μŠ€μ½”ν”„

varν‚€μ›Œλ“œλŠ” ν•¨μˆ˜ 레벨 μŠ€μ½”ν”„μ΄λ‹€.
ν•˜μ§€λ§Œ letν‚€μ›Œλ“œμ™€ const ν‚€μ›Œλ“œλ‘œ μ„ μ–Έν•œ λ³€μˆ˜λŠ” λͺ¨λ“  μ½”λ“œ 블둝(ν•¨μˆ˜,ifλ¬Έ, forλ¬Έ, whileλ¬Έ, try/catchλ¬Έ λ“±)을 μ§€μ—­ μŠ€μ½”ν”„λ‘œ μΈμ •ν•˜λŠ” 블둝 레벨 μŠ€μ½”ν”„λ₯Ό λ”°λ₯Έλ‹€.

 

let age = 27; // μ „μ—­ λ³€μˆ˜

{
  let age = 30; // μ§€μ—­ λ³€μˆ˜
  let name = 'song'; // μ§€μ—­ λ³€μˆ˜
}

console.log(age); // 27 
console.log(name); // ReferenceError: name is not defined

 

λΈ”λ‘λ ˆλ²¨ μŠ€μ½”ν”„μ΄κΈ° λ•Œλ¬Έμ— 블둝 μ•ˆμ˜ μŠ€μ½”ν”„μ—μ„œ μ„ μ–Έλœ ν•¨μˆ˜λŠ” 블둝 λ°–μ—μ„œ μ ‘κ·Όν•  수 μ—†λ‹€ 

κ·ΈλŸ¬λ―€λ‘œ name은 μ„ μ–Έλ˜μ§€ μ•Šμ•˜λ‹€κ³  인식이 λ˜λŠ” 것이닀 

 

ν•˜μ§€λ§Œ λ³€μˆ˜λ“€μ„ var둜 μ„ μ–Έν–ˆλ‹€λ©΄ λͺ¨λ“  λ³€μˆ˜λ“€μ΄ μ „μ—­λ³€μˆ˜λ‘œ ν˜Έμ΄μŠ€νŒ…λ˜μ–΄ 블둝 λ‚΄μ—μ„œ μ„ μ–Έν•œ λ³€μˆ˜λ“€μ˜ 값이 좜λ ₯이 λœλ‹€. 

 

ν˜Έμ΄μŠ€νŒ…

var와 let, constμ„ μ–Έμ˜ 차이 쀑 ν•˜λ‚˜λŠ” let, constκ°€ TDZ에 μ˜ν•΄ μ œμ•½μ„ λ°›λŠ”λ‹€λŠ” 것이닀.

즉, λ³€μˆ˜κ°€ μ΄ˆκΈ°ν™”λ˜κΈ° 전에 μ ‘κ·Όν•˜λ € ν•˜λ©΄, var처럼 undefinedλ₯Ό λ°˜ν™˜ν•˜μ§€ μ•Šκ³ , ReferenceErrorκ°€ λ°œμƒν•œλ‹€.

 

let age = 27;

function getAge() {
  console.log(age); // ReferenceError
  let age = 28;
};

 

μœ„μ˜ μ½”λ“œμ—μ„œ let으둜 μ„ μ–Έν•œ λ³€μˆ˜μ—μ„œ ν˜Έμ΄μŠ€νŒ…μ΄ μΌμ–΄λ‚œλ‹€λŠ” 것을 μ•Œ 수 μžˆλ‹€. 

ν˜Έμ΄μŠ€νŒ…μ΄ λ˜μ§€ μ•ŠλŠ”λ‹€λ©΄ console.log μ—μ„œλŠ” μ „μ—­μ—μ„œ μ„ μ–Έν•œ age인 27이 좜λ ₯이 λ˜μ–΄μ•Ό ν•˜μ§€λ§Œ 

ν˜Έμ΄μŠ€νŒ…μ΄ λ˜μ—ˆκΈ° λ•Œλ¬Έμ— ReferenceErrorλ₯Ό λ°œμƒμ‹œν‚€λŠ” 것이닀. 

 

undefinedλ₯Ό λ°˜ν™˜ν•˜λŠ” varμ™€λŠ” 달리, μ΄ˆκΈ°ν™”λ˜κΈ° 전에 μ ‘κ·Όν•˜λ©΄ μ—λŸ¬κ°€ λ°œμƒν•œλ‹€.

 

const의 μž¬ν• λ‹Ή κΈˆμ§€

 

const age = 27;
age = 28; // TypeError: Assignment to constant variable.

 

const둜 μ„ μ–Έν•œ λ³€μˆ˜λŠ” μž¬ν• λ‹Ήμ΄ κΈˆμ§€λ˜μ–΄μžˆλ‹€. ν•˜μ§€λ§Œ let으둜 μ„ μ–Έν•œ λ³€μˆ˜λŠ” μž¬ν• λ‹Ήμ΄ κ°€λŠ₯ν•˜λ‹€ 

 

const λ³€μˆ˜μ— 객체λ₯Ό ν• λ‹Ήν•œ 경우

 

const λ³€μˆ˜μ˜ νƒ€μž…μ΄ 객체인 경우, 객체에 λŒ€ν•œ μ°Έμ‘°λ₯Ό λ³€κ²½ν•˜μ§€ λͺ»ν•œλ‹€λŠ” 것을 μ˜λ―Έν•œλ‹€. ν•˜μ§€λ§Œ 객체 λ‚΄λΆ€μ˜ 값은 변경이 κ°€λŠ₯ν•˜λ‹€.

 

const person = { // 객체λ₯Ό μƒμˆ˜λ‘œ μ„ μ–Έ
  age: 27,
}

person = { // 객체가 λ‹΄κ²¨μžˆλŠ” μ°Έμ‘°λŠ” λ³€κ²½ λΆˆκ°€λŠ₯ λ•Œλ¬Έμ— Error
  age: 26,
}

person.age = 26; // 객체가 κ°€μ§€κ³  μžˆλŠ” valueλŠ” 변경이 κ°€λŠ₯

console.log(person.age)

 

 

정리

λ³€μˆ˜λ₯Ό μ„ μ–Έν•  λ•Œ var ν‚€μ›Œλ“œλ‘œ μ„ μ–Έν•˜κΈ° λ³΄λ‹€λŠ” let, const 둜 μ„ μ–Έν•˜λ„λ‘ ν•˜μž 

λ³€ν•˜μ§€ μ•ŠλŠ” 값이 ν•„μš”ν•˜λ‹€λ©΄ μƒμˆ˜λ₯Ό μ„ μ–Έν•  const ν‚€μ›Œλ“œλ₯Ό μ‚¬μš©ν•˜κ³  μž¬ν• λ‹Ήμ΄ ν•„μš”ν•˜λ‹€λ©΄ let ν‚€μ›Œλ“œλ₯Ό μ‚¬μš©ν•˜λ„λ‘ ν•˜μž.


Reference

 

https://ui.toast.com/weekly-pick/ko_20191014

https://wonism.github.io/is-let-hoisted/