[개념] 호이스팅

iamhyunji·2022년 5월 19일
3
post-thumbnail

🔍 들어가기 전에


회사 식사 시간 중, 선임 개발자분들께서 SQL과 Java, Javascript에 대한 얘기를 하셨다.
많은 주제 중, SQL은 Javascript처럼 호이스팅이 되지 않고, 순서대로 읽히는다는 얘기가 기억에 남았다.

주제 자체는 언어 간의 차이였으나 필자가 궁금한 것은 호이스팅이었다.
호이스팅은 무엇이며, 호이스팅이 된다는 것은 어떤 의미인지에 대해 궁금해졌다.

호이스팅이라는 용어는 종종 들어 봤고, 궁금할 때 개념도 간단히 찾아 봤다.

그렇지만 여전히 내게 낯설게 다가오는걸 보니, 이번 기회에 제대로 공부할 필요성을 느껴 찾아보게 된 오늘의 주제는 호이스팅이다.

📌 호이스팅


hoist - 네이버 사전

어려운 용어로 가득한 정의를 바로 보기 보다는 단어 그 자체가 주는 느낌을 알고 싶어 찾아봤다.

네이버 사전 기준으로 hoist는 대상을 위로 끌어올리는 행위 또는 물체를 의미한다.
크레인이나 로프와 같은 것을 이용해 특정 대상을 위로 올리는 것을 hoist라 한다.

현실에서 "끌어 올린다"는 개념으로 쓰이는 hoist, 프로그래밍에서는 어떨까?
프로그래밍 분야라고 완전히 다른 뜻, 다른 개념으로 사용할까?

아래의 MDN 공식 문서를 통해 확인해보자.

[MDN 공식문서]
소스 코드를 실행하기 전에, 인터프리터(interpreter)가 함수, 변수, 클래스의 선언을 해당 범위(Scope)의 상단으로 옮겨놓는 것을 의미한다.

말이 조금 어렵지만, 내용 중 상단으로 옮겨놓는 것이라는 구문을 통해 프로그래밍의 hoist 역시 특정 대상을 위로 끌어 올리는 행위를 의미한다고 말할 수 있다.

다만, 같은 개념이지라도 단어를 사용하는 분야의 차이가 있듯, 현실과 프로그래밍의 각 호이스팅은 끌어 올리고자 하는 대상의 차이가 있다.

프로그래밍에서 호이스팅은 함수, 변수, 클래스의 선언을 대상으로 한다.
함수, 변수, 클래스의 선언을 범위 내 상단으로 옮기는 것이 프로그래밍에서의 호이스팅이다.

💡 인터프리터(interpreter)란?

  • 프로그래밍 또는 스크립트 언어를 기계어 프로그램으로 사전에 컴파일 하지 않고, 프로그래밍 또는 스크립트 언어로 작성된 명령을 바로 읽어 실행하는 프로그램
  • 인터프리터 언어로는 JavaScript, Perl, Python, BASIC 등이 있음

📌 구분 및 특징


구분

앞서 얘기했듯 프로그래밍에서 호이스팅은 변수, 함수, 클래스 총 3개의 대상에 사용된다.

  • 변수 호이스팅
  • 함수 호이스팅
  • 클래스 호이스팅

호이스팅은 대상 각각의 선언에 대해서 동작하며, 호이스팅 된다는 것은 변수, 함수, 클래스 선언 전에 대상을 참조할 수 있음을 의미한다.

호이스팅이 무엇인지, 어떤 대상에게 사용되는지 알아봤다.
그렇다면 이 호이스팅은 왜 필요할까?
이는 호이스팅의 특징과 함께 알아보도록 하자.

특징∙사용 이유

  • Javascript의 기본 메커니즘
  • 어느 위치에 선언하든, 코드를 범위 상단으로 이동시킴
  • 변수 또는 함수 선언의 순서에 자유로움
  • 선언에 대해 호이스팅을 하지만, 그 외 Javascript 라이프사이클에 대해서는 호이스팅을 하지 않음

호이스팅은 Javascript의 기본 메커니즘이다.
정의에서 얘기했듯이 호이스팅은 변수, 함수, 클래스를 어느 위치에 선언하든, 코드를 범위 상단으로 이동시킨다.
그렇게 함으로써 Javascript 언어 사용자는 기본적으로 변수 및 함수의 선언과 호출 순서를 고려하지 않고도 자유롭게 프로그램 작성이 가능해진다.

정의와 특징 및 필요성에 대해 알아봤다.
이제부터 간략히 소개된 호이스팅의 구분에 대해 알아보고자 한다.

💡 Javascript 라이프사이클 ?

var num;		// 1. 선언
num = 1			// 2. 할당
num = num + 2	// 3. 사용
  • 선언
  • 초기화 / 할당
  • 사용

Javascript는 보통 3단계의 라이프사이클을 갖는다.

첫 번째는 선언 단계로, var(ES5), let(ES6), const(ES6)의 keyword를 통해 원하는 이름으로 변수를 선언한다.

두 번째는 초기화 및 할당 단계로, 선언 keyword에 따라 초기화 값은 달라질 수 있으며, 할당 연산자(=)를 통해 변수에 값을 할당한다.

마지막 단계는 사용하는 단계로, 로직에 따라 변수를 이용하는 단계이다.

📌 변수 호이스팅


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

Javascript는 변수 선언에 대해 호이스팅 한다.
즉, 프로그램 실행 시, var, let, const 키워드를 통해 선언된 부분들이 호이스팅 되어 선언 부분의 위치를 코드 범위의 최상단으로 이동시킨다.

여기서 선언 부분만 소스코드의 위치가 상단으로 이동시킬 뿐, 나머지(초기화/할당, 사용) 부분의 변동은 없다.

그렇다면 var, let, const 키워드로 선언한 모든 변수는 같은 결과를 낼까? 선언하지 않은 변수에 대해선 어떻게 결과를 반환할까?
아래에서 자세히 알아보자.

var 키워드

console.log(num);	// Output: undefined
var num = 1;

위 코드를 보면 Java와 같은 다른 언어에서는 Error를 예상했을 것이다.
그렇지만 undefined가 반환되었다.
그 이유는 호이스팅의 정의와 var 키워드 변수의 특징으로 설명할 수 있다.

호이스팅은 변수 선언 범위 내에서 변수 선언을 상단으로 끌어 올리는 것이다.
var 키워드로 선언된 변수의 범위는 현재 실행 컨텍스트(current execution context)이다.
현재 실행 컨텍스트는 애워싸는 함수(Enclosing Function) 내 또는 글로벌 영역이다.

또 var 키워드로 선언된 변수는 기본적으로 undefined로 값이 초기화된다.

그러니 우리 눈에는 저렇게 보이는 코드도 Javascript 백그라운드에서는 아래와 같이 해석된다.

var num;
console.log(num);	// Output: undefined
num = 1;

비록 우리는 선언과 할당을 맨 마지막에 적었으나, 호이스팅에 의해 변수의 선언이 상단으로 올라오고, 할당은 호이스팅 되지 않기 때문에 초기값인 undeinfed가 콘솔에 출력되었다.

let 키워드

let num = 99;

{
  console.log(num);	// Output: Reference Error : Cannot access 'num' before initialization
  let num = 1;
}

let의 범위는 함수가 아닌 블록 단위이다.
그렇기 때문에 let 키워드로 선언된 변수가 호이스팅이 되었는지 확인하려면 블록을 꼭 지정해줘야 한다.

그렇지만 블록 범위인 것을 감안 하더라도 var 키워드 선언 변수와 결과가 다르다!
왜 그럴까? 에러를 던지는 let은 호이스팅을 안 하는걸까?

아니다. let 또한 호이스팅을 한다.
만약 호이스팅을 안 했다면, 위 코드에서는 Reference Error가 아니라 99가 출력되었어야 한다.
다만 let은 undefined라는 초기값을 지정하는 var와 달리 초기값이 없다.
초기화되지 않은 상태에서 변수에 접근하니 Reference Error가 발생하였다.

Error가 출력되었다고 꼭 호이스팅을 안 하는 것이 아닌, 호이스팅을 했기 때문에 위 코드에서 Error가 출력되는 것이다.

const 키워드

const num = 99;

{
  console.log(num);	// Output: Reference Error : Cannot access 'num' before initialization
  const num = 1;
}

const 키워드 또한 let과 유사하게 동작하며, 호이스팅을 한다.

다만 let과의 차이점이라면, const는 변하지 않는 값을 사용하며, 선언 시 값을 같이 초기화/할당 해주어야 한다.

그렇지 않으면 호이스팅과 별개로 에러가 발생할 수 있으니 주의가 필요하다.

📌 함수 호이스팅


hoisted(); // Output: "Hoisted!!!!!"

function hoisted() {
  console.log('Hoisted!!!!!');
};

📌 클래스 호이스팅


var Frodo = new Hobbit();
Frodo.height = 100;
Frodo.weight = 300;
console.log(Frodo); // Output: ReferenceError: Hobbit is not defined

class Hobbit {
  constructor(height, weight) {
    this.height = height;
    this.weight = weight;
  }
}

🔗 참고•출처


profile
Lv0. 웹 개발 (❤️❤️❤️🤍)

0개의 댓글