[JS] 호이스팅(hoisting)에 대해 설명해주세요.

mimmi·2024년 9월 16일

JavaScript

목록 보기
1/10
post-thumbnail

😄 답변

호이스팅(Hoisting)은 JavaScript의 고유한 동작 방식으로, 변수함수 선언이 실제 코드 실행 전에 메모리 상에서 자동으로 상단으로 끌어올려지는 현상입니다. 그러나, 호이스팅의 동작 방식은 변수와 함수의 선언 형태에 따라 다릅니다.

  • 변수 호이스팅: var로 선언된 변수는 선언만 호이스팅되고 초기화는 나중에 이루어집니다.
  • 함수 호이스팅: 함수 선언식은 코드의 어디에서든 호출할 수 있도록 완전히 호이스팅됩니다. 반면 함수 표현식은 변수 선언만 호이스팅되고 함수의 할당은 나중에 이루어지므로, 선언 전에 호출하면 오류가 발생합니다.

1️⃣ 변수 호이스팅

  • 자바스크립트 코드는 인터프리터에 의해 한 줄씩 순차적으로 실행된다.
    → 자바스크립트는 인터프리터 언어

💡 인터프리터 언어

  • 개발자가 별도의 컴파일 작업을 수행하지 않는다.
  • 코드가 실행되는 단계인 ‘런타임’에 한줄씩 바이트코드로 변환 후 실행한다.
  • 자바스크립트는 런타임에 컴파일되며 실행 파일이 생성되지 않고 인터프리터의 도움 없이 실행할 수 없기 때문에 컴파일러 언어라고 할 수 없다!
항목컴파일러 언어인터프리터 언어
실행 방식소스 코드를 한 번에 모두 컴파일하여 실행 파일 생성 후 실행소스 코드를 한 줄씩 즉시 해석하며 실행
컴파일/해석 과정실행 전에 전체 코드를 컴파일하여 기계어로 변환실행 중에 코드 한 줄씩 해석 후 즉시 실행
속도실행 속도가 빠름 (한 번 컴파일된 후에는 반복적인 해석이 불필요)비교적 느림 (코드를 해석하면서 실행)
디버깅컴파일 타임에 오류가 모두 발견됨런타임 중에 오류가 발생할 수 있음
메모리 사용일반적으로 실행 파일이 미리 생성되어 더 적은 메모리를 사용즉시 해석 및 실행되므로 메모리 사용이 많을 수 있음
예시 언어C, C++, Go, RustPython, JavaScript, Ruby
배포기계어로 변환된 실행 파일을 배포소스 코드 자체를 배포해야 함
플랫폼 독립성플랫폼 의존적 (컴파일된 바이너리가 특정 플랫폼에서만 동작)일반적으로 플랫폼 독립적임 (인터프리터만 있으면 실행 가능)
초기 실행 준비 시간컴파일 시간이 필요하므로 느림즉시 실행 가능
  • 다음 코드를 봐보자.
console.log(score); // undefined

var score; // 변수 선언
  • 위 코드에서 참조에러(ReferenceError)가 발생하지 않고 undefined가 출력되는 이유는?
    • 변수 선언이 런타임(코드가 한 줄씩 순차적으로 실행되는 시점)이 아닌 그 이전에 실행되기 때문!!!!!!!!!
  • 원래 과정
    • 소스코드 실행을 위한 준비 단계인 소스코드의 평가 과정:
      자바스크립트 엔진은 변수 선언을 포함한 모든 선언문을 소스코드에서 찾아내 먼저 실행한다.
    • 소스코드의 평가 과정 → 변수 선언을 포함한 모든 선언문을 제외하고 소스코드를 한 줄 씩 순차적으로 실행
      • JS엔진은 변수 선언이 소스코드의 어디에 있든 상관없이 다른 코드보다 먼저 실행.
        • 어디에서든지 변수 참조 가능!
      • 변수 선언이 소스코드가 순차적으로 선언되는 런타임 이전에 먼저 실행된다는 증거!
  • 사실 변수 선언뿐 아니라 var, let, const, function, function*, class 키워드를 사용해서 선언한 모든 식별자 (변수, 함수, 클래스)는 호이스팅된다.
    • 모든 선언문은 런타임 이전에 먼저 실행되기 때문!

💡 변수 선언문이 코드의 맨 위로 끌어 올려진 것처럼 동작하는 자바스크립트의 고유특징
: 변수 호이스팅 (variable hoisting)

2️⃣ 함수 호이스팅

  • 이번엔 예제부터 봐보자
console.log(add); // f add(x,y)
console.log(sub); // undefined

console.log(add(2,5));
console.log(sub(2,5));

function add(x,y) {
	return x+y;
}

var sub = function (x,y) {
	return x-y;
}

💡 함수 선언식 vs. 함수 표현식

항목함수 선언식 (Function Declaration)함수 표현식 (Function Expression)
작성 방식function 키워드를 사용해 함수 이름과 함께 정의변수에 익명 함수 또는 명명된 함수를 할당하는 방식
호이스팅함수 선언이 호이스팅됨. 함수 선언 전에 호출 가능변수 선언만 호이스팅되므로 함수 정의 전에 호출 불가
호출 가능 시점함수 선언 이전에도 호출 가능함수 정의 이후에만 호출 가능
예시js function foo() { ... }js const foo = function() { ... }
이름 유무함수 이름이 반드시 필요함익명 함수 또는 명명된 함수 모두 가능
사용 시기함수가 코드 어디에서든 사용 가능하도록 정의하고 싶을 때특정 조건에 따라 함수가 동적으로 정의될 때 적합
  • 함수 표현식으로 정의한 함수는 함수 표현식 이전에 호출할 수 없다!
  • 함수 선언식으로 함수를 정의하면 런타임 이전에 함수 객체가 먼저 생성되고, JS 엔진은 함수 이름과 동일한 이름의 식별자를 암묵적으로 생성하고 생성된 함수 객체를 할당함.

💡 함수 선언문이 코드의 맨 위로 끌어 올려진 것처럼 동작하는 자바스크립트의 고유특징
: 함수 호이스팅 (function hoisting)

3️⃣ 함수 표현식 vs. 함수 선언문 vs. 변수선언문(var)

  • 초기화
    • 변수 선언문 (var) → undefined로 초기화

      • 선언문 이전에 변수 참조 → 호이스팅 → undefined
    • 함수 선언문 → 함수 객체로 초기화
      - 선언문 이전에 호출 → 호이스팅 → 가능!


  • 그럼 함수 표현식은…?
    • 함수 표현식은 변수에 할당되는 값이 뭘까?
      - 함수 리터럴
      - 변수 선언문 + 변수 할당문
      - 변수 할당문의 값은 할당문이 실행되는 시점(런타임)에 평가 되므로,
      함수 표현식의 함수 리터럴도 할당문이 실행되는 시점에 쳥가되어 함수 객체가 된다.
      - 따라서, 함수 표현식 → 함수 호이스팅이 아니라 변수 호이스팅이 발생함!!


    • 함수 표현식

      • 표현식 이전에 호출 → undefined를 호출하는 것과 같으므로 → 타입 에러
      • 함수 표현식으로 정의한 함수는 함수 표현식 이후에 참조 또는 호출을 해야함
      • 함수 선언문 대신 함수 표현식을 사용할 것을 권장함..!

0개의 댓글