앞서 작성했던 [JAVASCRIPT] 변수의 선언과 할당 에서 변수의 특징들을 설명하며 잠시 "호이스팅"에 대해 언급하였습니다. 오늘은 자바스크립트의 큰 특징 중 한가지인 호이스팅(Hoisting)에 대해 알아보도록 하겠습니다.
JavaScript 호이스팅은 인터프리터가 코드를 실행하기 전에 함수, 변수, 클래스 또는 임포트(import)의 선언문을 해당 범위의 맨 위로 끌어올리는 것처럼 보이는 현상을 뜻합니다.
-MDN Web Docs -
호이스팅(hoisting)
은 단어의 "hoist"의 의미 그대로 "끌어올리다" 라는 의미를 가지고 있습니다. MDN 문서의 나와있는 정의 그대로 선언문이 작성된 위치가 어느 곳에 있던 스코프(scope)의 최상단으로 올려지는 듯한 현상 그 자체를 의미합니다.
많은 사람들이 오해하기 쉬운 부분은 호이스팅(hoisting)
이 자바스크립트에서 제공하는 하나의 어떠한 개념이라고 생각하게 된다는 것입니다.
호이스팅(hoisting)
은 어떠한 개념이라기 보다 자바스크립트 엔진이 동작하는 과정에서 일어나게 되는 "현상"이라고 이해하면 쉽습니다.
호이스팅(hoisting)
이 일어나는 이유를 이해하기 위해서는 자바스크립트가 내부에서 변수를 선언하고 할당하는 과정인 실행 컨텍스트(Execution Context) 라는 개념을 자세히 알아볼 필요가 있습니다
자바스크립트 엔진은 코드를 실행하기 전 실행할 코드에 제공할 환경 정보들을 모아놓은 객체인 실행 컨텍스트(Execution Context)을 구성합니다. 여기에 담기는 정보는 1.Variable Environment
2.Lexical Environment
3.This Binding
3가지로 구분할 수 있는데, 호이스팅(hoisting)
과 관련된 개념은 1.Variable Environment
의 environmentRecord 과 관련되어 있습니다.
environmentRecord가 하는 일은 간단합니다. 코드를 실행하여 자바스크립트 엔진이 실행 컨텍스트를 구성할 때 식별자(변수, 함수명)을 수집합니다.
식별자 정보는 변수와 함수를 선언할 때 사용된 "이름"을 의미합니다.
다른 작업보다 environmentRecord가 가장 먼저 동작하다보니 자바스크립트 엔진이 함수를 실행하거나, 변수를 사용하기 전 이미 해당 함수나 변수의 식별자의 정보를 알고 있게 됩니다.
이렇기에 마치 선언문이 코드의 맨 최상단에 작성되어 코드가 실행 된 것처럼 보이기에 호이스팅(hoisting)
이라는 개념이 생겨나게 된 것입니다.
"실행 컨텍스트(Execution Context)"는 자바스크립트에서 가장 중요한 핵심 개념 중 하나이지만 내용이 많아 자세한 설명은 추후 따로 정리하여 올리도록 하겠습니다.
var
키워드를 이용하여 변수를 선언하였을 때, 머리를 쥐어짤 것 같은 문제가 발생한다는 것은 잘 알려져 있습니다. 그런데 많은 사람들이 함께 헷갈리는 것이 let
과 const
키워드를 통해 변수를 선언하였을 때도 "호이스팅(hoisting)"이 발생하는 것이냐 하는 의문을 가진다는 것입니다.
결론을 먼저 말하면...
var, let, const 모두 호이스팅(hoisting) 현상이 일어나는 것이 맞습니다!
그건 아마도 var
키워드의 특징 때문일 것입니다.
var
키워드와 let
, const
키워드의 다른 점 이라고 한다면, "var
키워드는 선언과 동시에 초기화가 진행된다." 는 것입니다.
var
변수는 코드 실행 시 선언과 동시에 "undefined"로 초기화가 진행되지만, 반면 let
과 const
는 선언과 초기화를 각각 따로 해줘야합니다.
즉, 각 키워드마다 변수가 선언되고, 초기화, 할당되는 방법이 다르기 때문입니다.
변수가 선언되고, 할당되어 사용되는 과정은 크게 3단계
로 나뉩니다.
선언 --> 초기화 --> 할당
사용할 메모리를 주솟값을 식별할 식별자(변수)를 등록하는 단계
// 변수 선언
var A;
메모리에 공간을 실제로 확보하는 단계. 기본적으로 undefined가 저장됨
대입 연산자=
를 통해 실제 사용할 값을 할당하는 단계
// 변수 할당
var A = 100;
✅ var
은 앞서 이야기 했듯 "선언"과 동시에 "초기화"가 일어납니다.
따로 초기화를 진행하지 않아도, 내부적으로 "undefined"로 초기화가 일어납니다.
✅ let
은 "선언"과 "초기화"를 따로 해줘야 합니다.
호이스팅(hoisting)이 일어날 때 즉, environmentRecord에 선언된 식별자가 먼저 수집이 되고, 실제 코드가 실행 될 때 초기화가 일어나게 됩니다.
이때 일시적 사각지대(TDZ: Temporal Dead Zone)의 영향을 받게 되는데, 선언과 초기화의 단계 사이에서 변수를 참조(사용)하게 되었을 경우 ReferenceError 에러를 발생시킵니다.
*일시적 사각지대(TDZ: Temporal Dead Zone)란?
변수의 선언부터 변수의 초기화가 이루어지기 전까지의 구간
✅ const
는 상수의 역할을 하기 때문에 선언, 초기화, 할당의 단계가 모두 동시에 일어나게 됩니다.
다시 본론으로 돌아와서 이야기 해본다면,
var
의 경우는 선언과 초기화가 동시에(자동으로 undefined) 일어나기 때문에 선언 후 사용하지 않아도 에러없이 자연스럽게 이용되고, 스코프(scope)의 범위가 변수의 선언과 할당에서 보았듯 "식별자의 유효범위가 함수 레벨"이기 때문에 호이스팅(hoisting)
으로 인해 중복선언이 일어날 가능성이 높아지게 되어 문제가 많이 발생 합니다.
let
과 const
의 경우에는 선언과 초기화의 단계가 각각 일어나기 때문에 일시적 사각지대(TDZ: Temporal Dead Zone)에 의해 영향을 받고, "식별자의 유효범위가 블록 레벨"에 있기 때문에 호이스팅(hoisting)
으로 인해 생기는 문제로 부터 자유로울 수 있었던 것 입니다.
호이스팅
을 통해 변수와 함수의 선언을 스코프(scope)의 최상단으로 끌어 올리게 되면 선언된 변수가 사용되기 전에 undefined로 초기화되거나 ReferenceError 에러를 발생시킨다고 배웠습니다.
이를 통해 변수가 선언만 되고, 아직 할당되지 않았을 때 발생할 수 있는 에러를 방지해줍니다.
따라서 코드를 작성할 때 변수를 선언하는 위치에 주의하지 않아도 되므로 실수를 줄일 수 있습니다.
호이스팅
은 변수와 함수의 스코프를 관리하는 데 도움이 됩니다.
변수 및 함수 선언은 해당 스코프 내에서만 유효하며, 호이스팅을 통해 스코프의 범위를 파악할 수 있습니다.
호이스팅
이 분명 코드를 작성할 때 도움이 되는 개념은 맞습니다. 하지만 호이스팅(hoisting)
을 믿고 중구난방으로 코드를 작성하기보다 처음부터 코드의 가독성과 유지보수를 고려해 개발하여 호이스팅이 발생하지 않도록 하는 것이 가장 좋은 방법일 것입니다.
호이스팅(hoisting)
으로 인한 문제를 방지하기 위해서는 다음과 같은 조치방법을 할 수 있습니다!!
var
대신 let/const
를 사용한다참고
taenami.tistory
gmlwjd9405.github.io
demain18-blog.tistory.com
hanamon.kr/
heycoding.tistory
책 <코어 자바스크립트> - 정재남