자바스크립트 호이스팅 ( Hoisting )

dongmin·2024년 4월 28일
2
post-thumbnail

🤔 시작하며

자바스크립트에서 변수 또는 함수를 호출한 뒤에 선언했는데 오류가 발생하지 않고 정상적으로 코드가 실행될 때가 있다.

console.log(a);		//undefined
var a = 1;

개발자 도구를 열어 결과를 직접 확인할 수 있다.

위의 예제 코드는 a 를 호출하고 난 뒤에 선언했지만 ReferenceError 가 발생하지 않고 undefined 가 출력된다.

인터프리터 언어

자바스크립트는 코드가 실행되는 런타임 때 한 줄씩 순서대로 실행되는 인터프리터 언어이다.

그런데 어떻게 선언하기 전에 호출하는 코드가 에러를 발생시키지 않고 정상적으로 실행될 수 있는 것일까?

이는 자바 스크립트의 호이스팅 덕분에 가능하다. 지금부터 호이스팅 에 대해서 자세히 알아보도록 하겠다.

🏗️ 호이스팅이란?

호이스팅은 끌어올린다 라는 뜻이다.

자바스크립트의 호이스팅은 함수와 변수의 선언을 위로 끌어올린다는 것이다.

주의해야할 점은 실제로 코드를 위로 끌어올리는 것은 아니고 자바스크립트 엔진이 실행 컨텍스트를 구성할 때 해당 컨텍스트에서 사용될 함수와 변수의 정보(식별자)를 먼저 수집하기 때문에 끌어올린다고 표현하는 것이다.

실행 컨텍스트에 대해 잠시 알아보자

실행 컨텍스트에는 variable environment , lexical environment , this binding 이 있는데 이 중 variable environment 안에 environment record 에 현재 컨텍스트와 관련된 식별자에 대한 정보가 있다.

즉, environment record 안에 식별자 정보가 있기에 컨텍스트는 변수나 함수가 호출되기 전에 이에 대한 정보를 알고 있기에 ReferenceError 가 발생하지 않는 것이고 이 현상을 호이스팅 이라고 한다.

예제 코드를 통해 이해해보자.

function example(x) {
  console.log(x);
  console.log(y);
  
  var x = 1;
  var y = 1;
}
example(2);

우선 exmaple(2) 가 호출될 때 컨텍스트는 새로운 환경을 구성한다.
새롭게 구성된 환경에는 example 함수에 필요한 example , x , y 에 대한 정보가 있다.

호이스팅에 의해 함수 안에서 선언이 먼저 될 것이다. ( 할당은 하지않는다 )
이를 시각화한 코드이다.

function example(x) {
  var x;	// 컨텍스트는 environment record 정보에 의해 x라는 변수가 사용될 것을 아는 것을 표현
  var y;	// 컨텍스트는 environment record 정보에 의해 y라는 변수가 사용될 것을 아는 것을 표현
  x = 2;	// 파라미터 값 할당
  console.log(x);	
  console.log(y);
  
  var x = 1;
  var y = 1;
}
example(2);

호이스팅에 의해 x , y 에 대해서 ReferenceError 가 발생하지 않고 x 는 parameter 값으로 할당되어 2 가 출력되고 y 는 선언만 되고 값이 할당되지 않은 시점에 console.log(y) 를 실행했기 때문에 undefined 를 출력한다.

개발자 도구에서 확인한 결과이다.

변수 호이스팅 - var, let, const 차이

호이스팅에서 var , let , const 의 차이를 느낄 수 있다.

console.log(a);		// undefined
console.log(b);		// ReferenceError
console.log(c);		// ReferenceError

var a = 1;
let b = 1;	
const c = 1;

개발자도구를 열어 직접 확인할 수 있다.

var 로 선언한 a 는 1로 정상출력이 되는데 letconst 로 선언한 bc 는 레퍼런스 에러가 발생한다.
이는 letconst 가 호이스팅 개념이 적용되지 않는 것이 아니다.

var 의 경우 선언부에서 초기화까지 하지만 letconst 의 경우 선언부에서 초기화를 하지 않기 때문에 호이스팅에 의한 선언부와 실제로 변수를 초기화 및 할당하는 시점 사이에 식별자만 존재하고 변수가 초기화되지 않은 TDZ (Temporal Dead Zone) 가 발생하기 때문에 ReferenceError 가 발생하는 것이다.

letconst 의 차이는 재할당을 할 수 있는가에 대한 여부이다.
let - 재할당 가능, const - 재할당 불가능

함수 호이스팅 - 함수 선언식, 함수 표현식 차이

함수 선언식

function a () {
  console.log("hello");
}

일반적인 함수를 선언하는 방식이다. 호이스팅시에 선언부, 초기화, 할당부 까지 모두 호이스팅된다.

함수 표현식

const a = function () {
  console.log("hello");
}

함수를 할당하여 사용하는 방식이다. 일반적인 호이스팅과 동일하게 동작한다.

예제코드를 통해 알아보자.

a(1,2);
b(3,4);

// 함수 선언식
function a (x,y) {
  console.log(x+y);
}

// 함수 표현식
const b = function (x,y) {
  console.log(x+y);
}

예제 코드의 결과이다.

함수 선언식으로 선언된 함수 a 는 호이스팅 할 때 선언부, 초기화, 할당까지 함수 전체가 호이스팅 되어 a(1,2) 실행으로 3 이 출력되었다.

반면, 함수 표현식으로 선언된 bconst 로 선언했기 때문에 const 의 호이스팅 방식과 같게 동작하여 선언부만 호이스팅 되어 ReferenceError 가 발생한다.

확실히 함수 선언식으로 사용하는 것이 편해 보인다.
하지만 함수 선언식은 같은 이름의 함수를 선언하게 된다면 문제가 발생한다.

a(1,2);
function a (x,y) {
  console.log(x+y);
}

a(1,2);
function a (x,y) {
  console.log(x*y);
}

결과가 3과 2가 출력되어야 할 것으로 생각했지만 2가 2 번 출력되었다.
이유는 함수 선언문의 호이스팅 방식에 의해서 함수 전체가 호이스팅 되어 실제로 다음과 같은 코드로 동작하는 것과 같다.


function a (x,y) {
  console.log(x+y);
}
function a (x,y) {
  console.log(x*y);
}

a(1,2);
a(1,2);

호이스팅에 의해서 두 번째로 선언된 a 함수만 2번 실행되는 것이다.
이런 함수 선언식의 호이스팅 방식에 의해서 예상치 못한 결과를 초래할 수 있으므로 함수 표현식을 사용하는 것이 더 좋은 방법이 될 수 있겠다.

📝 정리

호이스팅은 변수와 함수의 메모리 공간을 미리 할당하는 것을 의미한다.

실행 컨텍스트는 코드의 실행 환경을 추적하고 관리하는데 코드 실행 중에 변수와 함수에 접근이 가능해야 한다.

따라서, 호이스팅은 변수와 함수의 선언을 메모리에 등록하여 코드 실행 중에 변수와 함수에 접근할 수 있도록 함으로써 실행 컨텍스트가 코드의 실행 흐름을 관리 할 수 있도록 한다.

🙇🏻 마무리하며

자바스크립트의 동작 방식을 이해하는데 중요한 개념인 호이스팅에 대해서 알아보았다.

변수의 호출을 선언보다 먼저 했는데 오류가 발생하지 않는 현상이 신기해서 이유를 찾기 위해 검색하던 중 호이스팅에 대한 개념을 접하게 되어 공부하게 되었다.

이런 자바스크립트의 동작 방식을 이해하지 않으면 개발하는데에 있어서 예상치 못한 동작을 경험하는 일이 많을 것이라고 생각했다.

이러한 이유로 다음으로는 실행 컨텍스트에 대한 글을 작성해 볼 예정이다.

📕 Reference

profile
아이스박스

0개의 댓글