호이스팅

수박·2021년 8월 21일
0

JavaScript

목록 보기
21/22
post-thumbnail

호이스팅


먼저 염두에 둘 것들.

여기서 한가지 염두에 두고 글을 읽어야할 것이 있는데, JS엔진이 행하는 컴파일과정, 실행과정을 나누어서 생각을 해야한다.

컴파일은 말 그대로 실행전, 인터프리터가 코드를 실행할 수 있도록 준비해놓 단계이고 실행은 바이트코드로 이루어진 기계어를 실행하는 것이다.

호이스팅 ?

코드 실행 전, 컴파일 단계에서 메모리에 함수, 변수가 메모리에 저장되어(var한정, var는 선언과 동시에 초기화가 이루어짐으로서 메모리가 할당된다.) 선언문이 끌어올려지는 것처럼 표현되는 것.

선언과 할당을 분리해서 생각해야함. 선언부터 처리됨을 기억.

Hoisting은 아래에 있는 것을 들어올린다라는 뜻이다.

JS에서는 선언된 변수 및 함수를 코드의 상단으로 끌어올리는 것으로 얘기한다.

그럼 정말 물리적으로 코드가 맨위로 올라가서 실행되는 것인가 ?

No. 이해하기 쉽도록 그렇게 "설명"하는 것이다.

다음의 예제는 정말 많이 보았을 것이다.

console.log(농담곰); //undefined
var 농담곰 = 24;

농담곰이 선언되기이전, 호출되었으므로 참조에러가 날 것 같은데 그렇지 않다.

이게 호이스팅 때문이다(+var변수의 특성).

호이스팅으로 인해 왜 저런 현상이 발생하는지 차근차근 알아가보자

호이스팅이 일어나는 시점

호이스팅은 내가 이해하기로 코드 실행 전 선언이 먼저 수행되는 것으로 이해된다. 복잡한 개념이 아니다.

이전글에서 다루었듯, JS엔진은 처음 코드를 넘겨받아서 컴파일과정을 거친다.

저 끌어올려짐이라고 불리는 현상은 컴파일과정에서 발생한다.

컴파일과정에서 함수나 변수들이 "선언"되고 실행단계에서 값의 할당이 "실행"된다.

선언문에 대한 처리가 실행보다 먼저 수행되므로 var에 대한 선언은 할당보다 먼저 수행되는 것이다.

선언과 할당에 주안점을 두면서 코드를 보고 호이스팅에 대해서 정리를 해보자.

console.log(a)
var a = 10;
console.log(b)
var b = 20;
console.log(a);
function scope(){
 ...
}

위의 코드가 컴파일을 수행하면 엔진은 다음과 같이 코드를 바라본다.

실행단계에서 실행(console.log(a)) //아직 실행되는 게 아닙니다.
var a; //선언부터 처리합니다.
실행단계에서 실행(a = 10);
실행단계에서 실행console.log(b)
var b;//선언부터 처리합니다.
실행단계에서 실행(b = 10);
실행단계에서 실행(console.log(a);
function scope(){//선언부터 처리합니다.
	...
}

이처럼 엔진은 var a = 10

선언(var a)과 할당문(a = 10)으로 쪼개어 본다.

각각에 대한 처리는 다음과 같다.

선언문의 경우,

엔진은 위에서 아래로 코드를 읽으며 var a, var b와 같은 선언을 만나면 메모리가 할당된다. 스코프에게 a, b가 있는지 물어보고 없다면 스코프컬렉션에 추가, 있다면 그냥 지나친다. ->실행컨텍스트에서 다룸

할당문의 경우,

a = 10, b = 20를 실행시점에 실행할 코드로 변경해놓는다.

실행시점에서는 a, b가 스코프컬렉션에 있는지 확인 후, 있으면 해당 변수값을 할당하고, 없으면 스코프체인을 통해 상위로 올라간다.

컴파일단계인 지금 a=10과 같은 코드가 실행되는건 아니다. 먼저 선언을 처리하고 이후 실행단계에서 처리된다.

위의 코드가 실행단계에서 동작되는 순서는 다음과 같다.

//이미 메모리할당 완료- 
function scope(){ //변수보다 함수선언이 먼저 처리된다-실행컨텍스트에서 다룰예정
  ...
}
var a;
var b;

//이미 메모리할당 완료- 
  

//실행단계에서 수행될 코드들,
console.log(a) //undefined
a = 10;
console.log(b) //undefined
b = 10;
console.log(a); //10
//실행단계에서 수행될 코드들,

이미 상단의 선언문들은 컴파일단계에서 스코프의 결정, 메모리할당이 되었으므로 처리되지 않는다고 생각하면 된다.

하단 코드들이 순차적으로 실행된다.

첫 console의 a는 이미 컴파일단계에서 할당이 끝났으므로 참조에러가 아닌 undefined가 출력됨을 확인해볼 수 있다.


let, const도 호이스팅의 대상

변수의 생성단계

변수는 3가지 단계를 거쳐 생성된다.

  1. 선언단계 : 변수를 변수 객체에 등록. 이 변수 객체는 스코프가 참조하는 대상이 됨.
  2. 초기화단계 : 변수 객체에 등록된 변수의 공간을 메모리에 확보. 변수는 undefined로 초기화됨.
  3. 할당단계 : undefined로 초기화된 변수에 값을 할당.

여기서 var는 1,2단계가 동시에 이루어진다. 그 말은 즉,

값을 할당하지 않아도 메모리가 할당되어 선언 전, 콘솔로 참조할 수 있다.

console.log(a); // undefined
var a; //이미 선언과 동시에 메모리가 확보됨

반면, let은 그렇지 않다.

console.log(a); //ReferenceError: a is not defined
let a;

왜일까? let은 컴파일 때 선언이 먼저 이루어지는 호이스팅이 되지 않는 것일까 ?

let, const ?

let, const도 호이스팅의 대상이다.(즉, 선언부터 처리된다.)

그러나 호이스팅이 일어나지 않는 것처럼 보여진다.

그 이유는 var와 달리 let, const가 변수가 생성되는 방법이 다르기 때문이다.

let, const는 변수의 생성이 1,2단계가 한꺼번에 이루어지지 않는다.

초기화 이전 메모리 접근하려하면 참조에러가 발생한다.

//변수 생성이 1, 2단계로 각각 분리된다.
console.log(a); //참조에러 - 메모리에 없음
let a; //선언단계에서 이미 처리됨
a = 2; // 초기화단계 -> 메모리에 올라감

let a;를 선언해도 변수객체에 등록은 되나 메모리에 확보되지는 않는다.

따라서 메모리에 없는 값을 참조하기에 참조에러가 발생하는 것이다.

let, const로 선언된 변수의 값을 초기화하기 이전의 구역을 TDZ라고 하며 해당 구간에서는 변수에 대해 접근하려면 에러가 발생한다.

정리

자바스크립트 코드는 선언과 할당의 분리로 실행된다.

선언이 먼저 처리되고 이후 실행단계에서 할당문이 실행되므로, 선언 후 할당이 됨을 확인해볼 수 있다.

선언문이 최상단으로 끌어올려짐과 같이 이해할 수 있고 이를 호이스팅이라고 부른다.

호이스팅은 어느 글에서 보듯, 선언이 최상단으로 끌어올려지는 "기능"이라고 하지만 사실 컴파일단계에서 선언에 대한 것들을 먼저 처리하기에 끌어올려진 것처럼 "보여지는 것"이다.

"선언코드가 끌어올려져서 먼저 처리됩니다."가 아니라

"컴파일단계에서 선언이 먼저 처리되어서 선언코드가 끌어올려져보이는 것입니다."가 맞는 대답이라고 생각한다.

0개의 댓글