My Boundary As Much As I Experienced

JS) 호이스팅(Hoisting)이란? (var, let, const의 차이) 본문

FrontEnd/Javascript(Vanilla)

JS) 호이스팅(Hoisting)이란? (var, let, const의 차이)

Bumang 2023. 7. 20. 17:20

호이스팅이란?

함수 선언부가 유효범위의 최상단으로 끌어올려지는 효과를 말한다.
자바스크립트 파일을 컴파일러가 컴파일할 때, 함수 선언과 변수 선언들을 스크립트 최상단에서 해석한다.

 

 

함수 선언 이전에 함수를 호출할 시:

console.log(hello())
// hello

function hello() {
	return "hello"
}

만약 함수 '선언'을 아래에다 하고, 함수 호출을 위에서 할 시, 참조 에러가 뜨지 않는 이유는 함수 선언들을 미리 호이스팅하기 때문이었다.

 

 

함수 표현식을 쓰기 전에 호출할 시:

console.log(hello())
// Reference Error

const hello = () { // var, let, const 뭘로 하든 함수 표현식은 호이스팅이 안 된다.
	return "hello"
}

함수 표현식의 경우 호이스팅이 작동하지 않는다. var, let, const 모두 안 통한다.

 

 

변수 선언이 호이스팅이 된다고?

변수 선언 시 컴파일 되는 과정

1. 선언 (Declaration): 스코프와 변수 객체가 생성되고 스코프가 변수 객체를 참조한다.
2. 초기화(Initalization): 변수 객체가 가질 값을 위해 메모리에 공간을 할당한다. 이때 초기화되는 값은 undefined이다.
3. 할당(Assignment): 변수 객체에 값을 할당한다.

지금까지 선언 전에 변수를 사용하면 예외없이 에러를 겪었기 때문에 변수들이 호이스팅 된다는 것을 체감하지 못했다.

그 이유는 내가 let, const만 사용했기 때문이었고, var를 사용하면 let, const는 호이스팅이 되는 과정이 다르다.

 

var로 선언한 변수가 처리되는 과정

  1. var로 선언된 변수들은 일단 스코프 최상단에서 undefined로 초기화하여 호이스팅 된다.
  2. 그리고 자바스크립트 콤파일러가 스크립트를 읽어내려 선언문에 도달할 시 제대로 된 값이 지정된다.
  3. 그래도 선언 이전에 변수를 사용하면 undefined인 채로 사용은 가능하다.

 

let, const로 선언한 변수가 처리되는 과정(es6에 추가)

  1. let, const로 선언된 변수들은 일단 스코프 최상단으로 끌어올려 스코프 최상단에서 TDZ(일시적 사각지대)에 저장한다.
  2. (var와 똑같이) 자바스크립트 콤파일러가 스크립트를 읽어내려 선언문에 도달할 시 제대로 된 값이 지정된다.
  3. 그래도 선언 이전에  TDZ에 있는 것을 호출하면(변수를 사용하면) Reference Error가 뜬다.
console.log(word1) // undefined
console.log(word2) // Reference Error
console.log(word3) // Reference Error

var word1 = "apple"
let word2 = "banana"
const word3 = "orange"

 

var라는 녀석을 잘못 쓰면 골치아파지는 이유가 undefined로 호이스팅이 된다는 것이다. 차라리 빨리 에러를 뜨게 해주면 편한데, 어딘가에서 undefined인 채로 표류하는 변수가 생긴다면 골치 아파질 일이 생긴다... (이것 말고도 블록 스코프를 뛰어넘어 전역으로 사용 가능해서 골치 아팠던 경우도 생긴다...)

 

 

추가적인 var의 특징:

자신의 스코프를 넘어서 영향력을 미친다. if 문 같은데서 선언한 var문은 if문 바깥에도 영향력을 미친다. var로 선언된 변수는 모두 전역 변수로 처리된다. 이 점 매우 유의하여 사용해야 한다.

for (i = 0; i < 2; i++) {
	console.log(arr[i])
}

console.log(i) // 정상적으로 순회를 다 마쳤다면 2가 나온다.

 

개인적인 경험

개인적으로 처음 for문을 사용할 때 선언부에 let을 안 쓰고 i 변수를 사용한 적이 있었는데, 보통 처음부터 아무런 선언자를 안 쓰고 (i = 0처럼) 값을 할당하면 var로 처리된다.

다른 스코프에서 i를 쓰면 이전 for문의 i가 남아 있어서 예상치 못한 에러가 뜨는 경우가 많았다. (그래서 다시 i = 0을 재할당하거나 아예 다른 변수를 썼었음...) 그냥 for (let i = 0; ...) 으로 썼으면 그 스코프에만 i가 바인딩 되어, 다른 스코프에서 써도 상관없다.