Javascript를 사용 하다보면 호이스팅 이라는 말을 들어본 적이 있을 것이다. 실제로 나도 호이스팅 이라는 말을 들어본 적만 있고, 개념이 제대로 잡혀있는 것 같지 않아 블로그에 보기 좋기 정리하려고 한다.
들어가기에 앞서
호이스팅은 let과 const가 추가된 ES2015(ES6)에서부터 var를 사용하지 않으면서 중요도가 떨어졌다. 그래도 자바스크립트의 실행 환경을 이해하기 위해 알아두면 좋을 것 같다.
Hoisting의 뜻
네이버 영어사전을 통해 알아본 호이스팅의 뜻은, "끌어 올리기" 이다. 무엇을 끌어올린다는 것일까?
선언을 끌어올린다
MDN web Docs에서는 호이스팅을 "변수의 선언과 초기화를 분리한 후, 선언만 코드의 최상단으로 옮기는" 것 이라고 말하고 있다. 코드를 보면서 어떤 의미인지 이해해본다.
console.log(foo);
var foo = "hi";
// undefined
상단과 같은 코드를 실행한다면, 결과는 undefined이다. JAVA나 C++과 같은 언어였다면, 컴파일 과정에서부터 에러를 발생시켰을 것이다. 그러나 Javascript에서는 런타임에서도 에러는 발생하지 않고, 정의되지 않았다는 뜻의 undefined만 반환한다.
상단의 코드는 실행 환경에서 다음의 코드와 동일하게 동작한다.
var foo;
console.log(foo);
foo = "hi";
// undefined
이제 어떤 의미인지 감이 잡혔을 것이다. foo 라는 변수를 어떤 스코프에서 선언하였다면, 해당 선언은 자바스크립트 인터프리터가 가장 먼저 처리하도록 되어있기 때문에, 선언된 스코프 최상단으로 이동한다. 이때 주의할 점은, 선언과 동시에 초기화 (var foo = "hi") 했다고 해도 선언만 뜯어져서 올라간다는 점이다. 해당 변수에 값 할당은 실제로 선언과 동시에 초기화 코드를 작성한 곳에서 진행된다.
해당 스코프에서 최상단으로 끌어올리는 것이기 때문에 함수 내에서 변수가 선언되었다면 함수 최상단으로, 전역 컨텍스트에서 변수가 선언되었다면 전역 컨텍스트 최상단으로 끌어올려진다.
함수 선언문
다음 코드가 어떻게 동작할 지 예상할 수 있을 것이다.
console.log(typeof foo);
var foo = function() {
return "fooooo";
}
결과는 undefined 이다. 함수 표현식을 통해 함수를 할당하더라도 당연히 호이스팅은 일어난다. 변수 선언 시점에서 rValue는 신경쓰지 않고 호이스팅이 일어나기 때문이다.
그런데 이럴 때는 어떨까?
console.log(typeof foo);
function foo() {
return "fooooo";
}
함수 선언문을 통해 함수를 선언한 경우, 통째로 끌어올려진다. 따라서 해당 코드의 출력은 function 이고, typeof foo를 foo() 로 바꾸어 호출해도 잘 동작한다.
console.log(foo());
function foo() {
return "fooooo";
}
// fooooo
let과 const는 호이스팅이 일어나지 않는다?
정확히 말하면 이는 틀린 말이다. let과 const도 호이스팅된다. 이는 TDZ(Temporal Dead Zone)과 관련이 있다.
console.log(foo);
const foo = "hi";
// ReferenceError: Cannot access 'foo' before initialization
호이스팅을 설명하는 예제코드에서 var를 const로 바꾸면 코드가 실행되지 않고 에러를 뱉는다. 이를 보고 const(또는 let)은 호이스팅이 일어나지 않는다고 생각할 수 있다. 그러나 호이스팅은 분명히 일어난다. 다만, 초기화(할당) 되기 전까지는 해당 변수는 TDZ에 들어가 있기 때문에 사용하려고 하면 ReferenceError를 뱉는 것이다. 이는 예측 불가능한 코드를 막기 위해 이렇게 설계된 것이라고 한다.
이때문에 const는 선언과 동시에 초기화해야 한다. (let은 할당이 바뀔 수 있기 때문에 선언과 동시에 초기화하지는 않아도 된다 이러면 해당 라인에서 undefined로 초기화 한 것처럼 작동한다) 만약 선언과 동시에 초기화하지 않는다면, 자바스크립트 엔진은 언제 해당 변수를 TDZ에서 꺼낼지(엑세스할 수 있게 만들지) 알 수가 없다.
호이스팅의 개념에 대해서는 충분히 설명이 된 것 같으니, 해당 글은 여기까지만 작성하고 TDZ에 대해서는 나중에 따로 정리해야겠다.
'Study > JavaScript & Typescript' 카테고리의 다른 글
[JS] 클로저(Closure)와 렉시컬 스코핑 (0) | 2021.12.17 |
---|---|
[JS] 자바스크립트의 동작 원리 (0) | 2021.12.09 |
[JS] this 부터 call, apply, bind 까지 (0) | 2021.09.26 |
댓글