Javascript

[Javascript] 호이스팅 이해하기

minjaem 2023. 3. 19. 00:14

1. 호이스팅(Hoisting) 제대로 이해하기

호이스팅 ?

인터프리터가 변수와 함수의 메모리 공간을 선언 전에 미리 할당하는 것을 의미합니다. var로 선언한 변수의 경우 호이스팅 시 undefined로 변수를 초기화합니다.반면 let과 const로 선언한 변수의 경우 호이스팅 시 변수를 초기화하지 않습니다.
- MDN 공식 문서 

 

 그렇다. 호이스팅을 흔히, 코드를 최상단으로 끌어올린다고 하지만 작동 방식을 비유법으로 표현한 것으로 실제로 코드를 최상단으로 끌어올려지지 않는다.

 

호이스팅을 제대로 이해하려면 '환경 레코드(Environment Record)'를 알아야한다.

 환경 레코드에 변수가 어떻게 저장되는지만 봐도 호이스팅의 동작 원리를 이해할 수 있다.

환경 레코드는 프로그램을 평가하는 시점에 선언되는 변수를 기록하게 되는 곳인데, 프로그램을 평가할 때 환경레코드에 기록되어 있는 변수들을 참조하거나 업데이트하는 과정을 거치게 된다.

 그렇다면, 우리는 var, let, const가 환경레코드에 어떻게 기록되는지 이해하면 된다.

먼저 이해하기 위해선 선언(Declaration)식별자(Initialization)을 이해해야 한다. 선언이란, 메모리 공간을 확보하고 식별자와 연결하는 것이며 초기화란, 식별자에 암묵적으로 undefined 값을 바인딩하는 것이다. 

var는 선언과 초기화가 동시에 이루어지기 때문에 선언문 이전에도 변수를 참조할 수 있다.

반면에, let과 const는 선언만 이루어지기 때문에 선언문 이전에 변수를 참조할 수 없다. 

이를 TDZ(Temporary Dead Zone) 일시적 사각지대라고 한다. 즉, let 또는 cosnt로 선언했을 때 선언 이전에 식별자를 참조할 수 없는 구역을 의미한다. let과 const가 ES6 이후에 추가된걸로 보아 자바스크립트에서도 '선언 라인 이전에는 변수를 참조할 수 없다'는 일반적인 프로그래밍 방식을 추구할 수 있도록 보완되었다고 할 수 있겠다.

 var, let, const는 환경레코드에서 메모리 공간을 확보하고 식별자와 연결하기 때문에 모두 호이스팅을 한다.

var, let, const 또 다른 차이

1. var

  • 함수레벨 스코프를 가진다.
    • 즉, 선언부가 함수 안이기만 하면 언제든 변수를 사용할 수 있다.
function foo() {
	let a = true;
    
    if(a) {
    	const b = "나는 const"
    	let c = "나는 let"
    	var d = "나는 var. 어디든 돌아다니지"
    }
    

    console.log(d) // "나는 var. 어디든 돌아다니지"
}
  • var 없이 선언할 수 있다.
    • 이때는, 프로그램을 실행하는 도중에 디스 바인딩 컴포넌트가 가리키는 객체의 프로퍼티로 추가된다. 전역 객체의 디스 바인딩 컴포넌트는 전역 객체를 가리키므로 결국 전역 객체의 프로퍼티가 된다.
  • 재선언과 재할당을 할 수 있다.

2. let 

  • 블록수준 스코프를 가진다.
function foo() {
	let a = true;
    
    if(a) {
    	const b = "나는 const"
    	let c = "나는 let"
    	var d = "나는 var. 어디든 돌아다니지"
    }
    

    console.log(c) // "Uncaught ReferenceError: c is not defined"
}
  • 재선언은 불가능하지만, 재할당은 가능하다

3. const

  • let과 마찬가지로 블록수준 스코프를 가진다.
function foo() {
	let a = true;
    
    if(a) {
    	const b = "나는 const"
    	let c = "나는 let"
    	var d = "나는 var. 어디든 돌아다니지"
    }
    

    console.log(b) // "Uncaught ReferenceError: b is not defined"
}
  • 재선언과 재할당 모두 불가능하다.

 

결론

 ES6 이전에는 변수를 var를 사용할 수 밖에 없었고, 변수 선언 이전에 전역 변수로서 참조할 수 있다는 방식은 여러 심각한 문제를 일으켰다. 유효 범위가 넓어서 어디에 어떻게 사용될 것 인지 파악하기가 힘들고, 비순수 함수에 의해 의도하지 않게 변경될 수도 있어 복잡성을 증가시키는 원인이 된다. 따라서 var와 함수 선언식의 사용을 최대한 지양해야하고, let/const와 함수 표현식으로 사용을 해야 한다.

 

 

 

[참고]

https://www.youtube.com/watch?v=EWfujNzSUmw&t=191s&ab_channel=%EC%9A%B0%EC%95%84%ED%95%9C%ED%85%8C%ED%81%AC 

https://poiemaweb.com/es6-block-scope