호이스팅이란 선언된 변수, 함수의 선언부를 스코프에 따라 최상단으로 끌어올리는 개념입니다.
이는 hoisting
영단어 뜻 그대로임을 확인할 수 있습니다.
hoisting
(명사) 끌어 올리기, 들어올려 나르기 -네이버 영어사전 -
var number = 10;
위의 코드는 아래와 같이 나누어 볼 수 있는데요, 이 때 선언부에 해당되는 내용만 최상단으로 끌어올려줍니다.
var number; // *선언*
number = 10; // 할당(초기화)
console.log(one); // undefined
var one = 1;
위의 예제를 보면, 변수 one
을 선언하기도 전에 console
로 호출했으니 다른 언어라면 에러가 생기는 상황일 것입니다. 하지만 JavaScript는var
로 선언한 변수의 경우, 호이스팅 시 undefined
로 변수를 초기화합니다. 이에 따라, undefined
를 출력하는 것을 확인할 수 있는데요! 이는 JavaScript의 호이스팅 으로 인해 생기는 현상입니다.
그렇다면 var
로 변수를 선언한 경우, 호이스팅 시에 왜 undefined
를 출력하는걸까요?
undefined
가 뭐길래!
undefined
: 아직 할당하지 않은 값
undefined란, ‘아직 할당하지 않은 값’을 의미합니다. 위의 예제 코드를 JavaScript 내부에서는 어떻게 해석하고 있는지 아래의 코드를 통해 살펴보면 왜 undefined
가 출력되는지 알 수 있습니다.
// var one;
console.log(one); // undefined
var one = 1;
var
로 선언한 변수 one
은 호이스팅이 되어 선언부만이 상단으로 끌어올려집니다.
따라서 첫 줄의 변수 one
은 선언만 되어 있고 값은 할당되어있지 않은 상태인데요. 바로 이럴때의 변수 one
은 JavaScript의 자료형 중 하나인 undefined
인 상태라고 할 수 있습니다.
위의 예제와 같은 상황은 함수 내부에서도 동일하게 작용합니다.
function number(){
console.log(one);
var one = 1;
console.log(one);
}
number();
// undefined
// 1
호이스팅은 선언부만 끌어올린다는 것을 지금까지 설명했는데요, 그렇다면 변수 선언 없이 할당만한 상태라면 어떨까요?
console.log(one); // ReferenceError
one = 1; // 할당(초기화)
이때에는 호이스팅 발생하지 않고 ReferenceError
가 뜨는 것을 확인할 수 있습니다.
var
변수 선언과 함수 선언식일 때 호이스팅된다고 기억하고 있자!
1. 변수
변수 선언 방식var
,let
,const
모두 호이스팅의 대상이긴 하지만var
로 선언한 변수만 위로 끌어올려집니다.
2. 함수
또한, 함수를 선언하는 방식으로 함수 선언식과 함수 표현식이 있는데 이 중, 함수 선언식에서만 호이스팅이 일어납니다.
var
var one = 1;
을 보고 JavaScript는 선언부인 var one
만을 최상단으로 끌어올립니다. 이에 따라, 선언은 되어있지만 할당된 값이 없다는undefined
를 출력하는 것을 확인할 수 있습니다.
// var one;
console.log(one); // undefined 출력
var one = 1;
let
과 const
앞서 말했듯, let
과 const
역시 JavaScript의 변수 선언 방식이므로 호이스팅의 대상이기는 합니다. 하지만 선언부가 끌어올려지지는 않고 Error
가 나는 것을 확인할 수 있습니다. JavaScript 내부적으로 접근은 하지만 실제 끌어올려지지는 않는다는 것!
console.log(one); // ReferenceError 발생
let one = 1;
위의 코드는 실제 console창에서 아래와 같이 ReferenceError
가 뜨는 것을 확인할 수 있어요.
ReferenceError
: 존재하지 않는 변수를 참조했을 때 발생하는 오류
그렇다면 왜 let
과 const
로 변수 선언시 ReferenceError
가 발생하는 걸까요?
var
로 선언한 변수의 경우, 호이스팅 시 undefined
로 변수를 초기화합니다. 반면 let
과 const
로 선언한 변수의 경우 호이스팅 시 변수를 초기화하지 않습니다.
📜 MDN
let
변수는 초기화하기 전에는 읽거나 쓸 수 없다. 초기화 전에 접근을 시도하면ReferenceError
가 발생한다. 변수 스코프의 맨 위에서 변수의 초기완료시점까지의 변수는 “시간상 사각지대”(TDZ; Temporal Dead Zone)에 들어간 변수라고 표현한다.
JavasScript 함수 선언 방법으로는 함수 선언식과 함수 표현식이있습니다.
함수 선언식은 별도의 할당 명령 없이 function
키워드를 이용해 함수명, 인자, 내부 코드 작성하는 방식으로, 호이스팅의 대상입니다.
sayHi(); // hi
function sayHi(){
console.log("hi");
}
위와 같이, 함수 선언식으로 선언한 sayHi
함수는 호이스팅의 대상이 되어 함수를 선언하기 전에 호출하여도 정상적으로 결과가 출력되는 것을 확인할 수 있습니다.
var
함수 표현식은 변수 안에 함수를 할당하는 형태로, 호이스팅의 대상이 아닙니다.
sayHi(); // TypeError 발생
var sayHi = function(){
console.log("hi");
}
위 코드에서 sayHi
함수는 함수 표현식으로 선언되어있습니다. 이 때, console
창에 TypeError
가 발생하는 것을 확인할 수 있는데요.
TypeError
: 일반적으로 값이 기대하던 자료형이 아니라서 연산을 할 수 없을 때 발생하는 오류
함수 표현식은 호이스팅의 대상이 아니라고는 하는데... 그렇다면 왜 호이스팅되지 않는걸까요? 아까 변수 선언할 때에는 var
로 선언한 변수가 호이스팅의 대상이라고 했는데 말이죠.
이 때, JavaScript의 내부 동작을 보면 쉽게 이해할 수 있습니다.
// var sayHi; // undefined
sayHi(); // sayHi는 함수 아닌데 왜 함수 호출해?
var sayHi = function(){
console.log("hi");
}
var
로 선언한 변수는 호이스팅이 발생해 선언부만 최상단으로 끌어올립니다. 이에 따라, JavaScript는 선언부인var sayHi
만을 끌어올리게 되죠.sayHi
는 선언은 되어있지만 할당값이 없으므로 JavaScript 자료형 중undefined
인 것을 알 수 있습니다.sayHi
의 자료형이undefined
라고 알고 있던 JavaScript는 두번째 줄을 보고 당황합니다.sayHi
를 함수로 호출하고 있기 때문이죠.- JavaScript 자료형은
number
,bigint
,string
,boolean
,undefined
,null
,symbol
,object
로 8가지인데요. 여기서 함수는object
에 속합니다.- 따라서
undefined
자료형으로 생각하고 있던 변수를 함수로 호출하고 있기에TypeError
가 발생하게 되는 것입니다.
let
과 const
호이스팅 영향을 받지않는 let
이나 const
를 사용하면 ReferenceError
가 발생합니다.
sayHi(); // ReferenceError
let sayHi = function(){
console.log("hi");
}
🤔 호이스팅의 영향을 최소화하자!
변수 선언으로는 const
와 let
을 사용하는 것이 좋다는 의견이 압도적이지만, 함수 선언 방식은 의견이 분분하다는 것을 알게됐다. 코드를 유연하게 짜기 위해 함수 선언식을 사용하는 것이 좋다는 말이 있는가 하면, 호이스팅의 영향을 최소화하기 위해 함수 표현식을 사용하는 것이 좋다는 말도 있었기 때문이다.
따라서, 호이스팅이 무엇인지와 그 대상은 무엇인지를 정확히 인지하고 있는 것이 중요할 것이란 생각이 들었다. 그래야 왜 코드가 꼬였고 에러가 발생했는지를 보다 빠르게 찾을 수 있을 것 같다. 개인적으로는 함수를 선언할 때에도 코드가 순서대로 동작할 수 있도록 작성하여 호이스팅의 영향을 최소화하는 것이 효율적으로 보인다.
🤯 다른 사람에게 설명할 수 있어야 한다!
그동안 선언부만 끌어올린다는 개념이 참 와닿지 않아 호이스팅이 어렵게만 느껴졌었다. 하지만, 이번 위코드 사전스터디를 계기로 호이스팅을 자세히 공부하고 다른 사람에게 설명하며 참 도움이 많이 됐다. 내가 공부한 개념을 다른 사람이 들어도 알기 쉽게 설명할 수 있어야 비로소 내 것이 됨을 느꼈다. 혼자 이해하고 넘어가지 말고, 블로그를 통해서라도 설명하며 지식을 온전히 내 것으로 만들자!!!
자바스크립트(JavaScript) - 호이스팅(Hoisting)
JS의 호이스팅과 var, let, const의 차이점
모던 JavaScript 튜토리얼