💡 자바스크립트를 사용하면서 어떤 변수는 undefined를 뿜어내고, 어떤 경우에는 Uncaught ReferenceError: Cannot access ~ before initialized 라는 오류를 내뿜는 것을 볼 수 있었습니다. 선언은 되어 있지만 값이 할당되지 않은 경우, 오류가 나지 않고 값을 끌어올린다는 개념의 호이스팅. 공부해보며 좀 더 자세하게 살펴보겠습니다!


자바스크립트 엔진의 메모리 세팅

자바스크립트 엔진은 스크립트를 받게되면, 가장 먼저 하는 일이 메모리를 세팅하는 것입니다. 이 단계는 코드가 실행되기 전 단계이며, 쉽게 말해서 실행을 하기 전에 준비단계 정도입니다.

함수가 저장되는 방식과 변수가 저장되는 방식은 조금 차이가 있습니다.


함수

함수의 경우에는 전체 함수에 대한 참조와 함께 저장이 됩니다.

function sum (x, y) {
  return x + y;
}
NAME VALUE
sum < function >


변수

자, 우리 자바스크립트에서는 변수를 선언하는 방식이 대표적으로 3가지가 있다는 것을 알고 있습니다! var와 ES6에서 추가된 const, let 이렇게 3가지가 있죠?

여기서 주의 깊게 보셔야할 것이 바로 이 const, let인데, 이유는 이 두 변수들은 초기화가 되지 않은 상태로 저장된다고 합니다. 반면에 var로 선언된 변수들은 default로 undefined가 저장된다고 합니다.

const name = "Yu Jin";

let info = {
  height: 123;
  weight: 12
};

var city = "Suwon";
NAME VALUE
name < uninitialized >
info < uninitialized >
city undefined


실제 코드 실행

메모리에 생성단계가 끝나고나면 실제로 코드를 실행합니다.

자! 만약에 파일의 맨 첫문장에 console.log 구문이 있다고 합시다. ☞ 이는 변수들의 실제적인 선언 전의 zone이라고 해서 temporal dead zone이라고도 부릅니다.


함수

함수의 경우는 전체 함수 코드에 대한 참조와 함께 저장되었기 때문에 함수를 생성하기 전에도 호출이 가능니다.


변수

그렇다면 변수는? 우선, var의 경우는 변수가 선언되기 전부터 참조를 하게되면 undefined를 return할 것입니다.

하지만 const, let의 경우는 uninitialized이기 때문에 ReferenceError를 return 합니다.


메모리에 실질 값 저장

자바스크립트 엔진이 변수를 실질적으로 선언한 라인을 넘어가면 메모리에 있는 값들이 실제로 선언한 값들로 덮어 씌워집니다.

NAME VALUE
sum < function >
name “Yu Jin”
info < object >
city “Suwon”



호이스팅

이제 호이스팅에 대해서 좀 더 자세하게 살펴보겠습니다!

호이스팅의 대상은

  • var로 선언한 변수
  • 함수 선언문

입니다.


변수에서의 호이스팅

위에 메모리 세팅에 관한 설명을 보셨 듯, const, let은 uninitialize로 세팅되는 반면, var는 undefined로 세팅되는 것을 알 수 있습니다. 그래서 var은 호이스팅의 대상이 된다고 보시면 될 것같습니다.

console.log(duck); // undefined
var duck = "Pretty Duck";
console.log(dick); // Pretty Duck

위의 코드를 보면 가장 첫번째 문장이 undefined로 출력되는 것은,

var duck;
console.log(duck); // undefined
duck = "Pretty Duck";
console.log(dick); // Pretty Duck

다음처럼 가장 최상단으로 끌어올려지는 호이스팅이 일어났기 때문입니다.


함수 선언문과 함수 표현식에서의 호이스팅

함수 선언문과는 달리, 변수에 할당되는 함수 표현식의 경우는 끌어올려지지 않아 호이스팅이 되지 않는다고 하는데요, 이는 변수의 스코프 규칙을 따른다고 합니다.

함수 표현식

duckGroup(); // duckGroup is not a function

var duckGroup = function() {
  console.log("a is not a function");
};

위 코드에 duckGroup is not a function라는 에러가 출력되는 이유는,

var duckGroup;
duckGroup(); // duckGroup is not a function

duckGroup = function() {
  console.log("a is not a function");
};

다음처럼 duckGroup이라는 변수가 최상단으로 끌어올려져서 아직 함수인지를 모르는 상태에서 호출을 했기 때문입니다.


함수 선언식

반면, 함수 선언식은 스코프 내 어떤 위치에서 함수를 선언하든지 호출을 할 수 있습니다.

duckName();

function duckName(){
  console.log('pretty duck');
}
function duckName(){
  console.log('pretty duck');
}

duckName();


호이스팅을 왜 알아야하나요?

사실상 코드의 가독성과 유지보수를 위해서는 호이스팅이 되도록이면 일어나지 않도록 하는 것이 좋습니다. 그렇기 때문에 가능하면 변수나 함수를 가급적이면 상단부에 선언을 하고 const, let을 사용하는 편이 좋다고하네요.

그래도 우리는 var가 어떻게 동작하는지는 알아야하기 때문에 호이스팅의 개념이 중요하게 여겨지는 것같습니다. 아직 ES6가 어디에서든지 사용 가능하지 않은 한계 때문인 것같네여ㅠㅠ




참고

https://kkangdda.tistory.com/73