알아보자...!
일단 다음 코드부터 살펴보자
console.log(message) //undefined
var message='hello world'
message라는 변수를 선언하기 전에 console.log
를 사용해 접근했기 때문에 다른 프로그래밍 언어처럼 오류가 날 것 같지만 자바스크립트는 에러를 내지 않는다. 왜냐하면 호이스팅이라는 것 때문이다. 변수 선언이 코드의 선두로 끌어올려진 것처럼 동작하는 것이 호이스팅이다. 실제로 코드가 맨 앞에 위치하게 되는 것이 아니라 자바스크립트 parser가 내부적으로 끌어올려서 실행하는 것이다. 또한 모든 선언이 전역 최상단에서 선언 되는 것이 아니라 함수 유효범위의 최상단에서 선언된다. 변수뿐만 아니라 var
, let
, const
, function
, function*
, class
키워드를 사용해서 선언하는 모든 식별자는 호이스팅된다.
호이스팅이 발생하는 이유는 자바스크립트가 코드를 실행하는 방식과 관련이 있다. 자바스크립트 엔진은 런타임 이전에 각종 변수, 함수, 클래스 등을 메모리에 저장하기 때문에 호이스팅이 발생하는 것이다.
위의 코드 var message='hello world'
는 변수 선언과 값의 할당을 한 번에 한 것이다. 위 코드 실행 결과가 undefined
가 되는 것을 확인할 수 있는데 변수 선언은 호이스팅되어 범위 내의 최상단으로 끌어올려지게 된다. 실제로 선언 과정만 런타임 이전에 실행되고, 값의 할당은 런타임 시에 발생하기 때문에 위와 같은 결과가 나타난다.
(자바스크립트는 var
키워드로 변수를 선언하면 일단 암묵적으로 undefined
를 할당해 초기화한다..!)
두번째 예제를 보자
//case 1
printHello() //hello
function printHello(){
console.log('hello')
}
//case2
printWorld() //TypeError: printWorld is not a function
var printWorld=()=>{console.log('world')}
case 1은 function
키워드로 함수를 선언한 것이고, case 2는 var
키워드로 함수표현식 선언한 것이다. case 1에서는 정상적으로 ‘hello’
가 출력되는 반면 case 2에서는 printWorld is not a function
이라는 TypeError
가 발생한다. 그 이유는 function
키워드는 함수를 선언하는 것이라 호이스팅된 것이다. 반면 var
키워드를 이용해 printWorld 함수를 선언했기 때문에 printWorld는 함수로 취급되지 않고 호이스팅되어 undefined
가 할당된다.
❗ let
이나 const
를 사용하자
사실 위에서 살펴본 호이스팅은 직관적이지 못하고, 유지보수하기에도 힘들기 때문에 ES6의 let
/const
키워드를 사용하는 것이 좋다.let
이나 const
를 사용하여 변수를 할당하는 방법도 호이스팅이 되기는 하지만 값이 할당 되기 전까지는 접근할 수 없다. let
이나 const
를 사용할 때 값이 할당되기 전에 변수를 읽으면 에러가 발생하기 때문에 직관적인 코드를 작성할 수 있다. 따라서 var
를 사용하기 보다는 let
/const
를 사용하는 것이 좋다.
console.log(a); //undefined
var a=1;
console.log(b); //ReferenceError: b is not defined
let b=2;
console.log(c); //ReferenceError: c is not defined
const c=3;