호이스팅 (Hoisting)
호이스팅(Hoisting)에 대해 설명하는 페이지입니다.
Tags
JavaScript, Hoisting
개요
자바스크립트에서 호이스팅에 대해 정리한 페이지입니다.
호이스팅이란?
자바스크립트에서 호이스팅(Hoisting)
은 변수, 함수, 클래스, 임포트(import) 선언이 실행되기 전에 해당 선언이 코드의 최상단으로 끌어올려지는 것처럼 동작하는 자바스크립트의 동작 방식을 말합니다. 실제로 코드가 이동하는 것은 아니지만, 선언이 실행 컨텍스트의 생성 단계에서 메모리에 미리 저장되기 때문에 런타임 시 선언된 것처럼 사용할 수 있습니다.
변수 호이스팅
변수의 경우 변수 선언 방식(var
, let
, const
)에 따라 호이스팅 동작 방식이 다릅니다.
var
변수 호이스팅
var
키워드로 선언한 변수는 변수 선언 부분과 초기화(undefined)가 호이스팅됩니다. 따라서 변수 선언 전에 접근하면 undefined가 반환됩니다.
예를 들어 다음과 같이 선언되지 않은 변수에 접근하려고 시도한 경우 ReferenceError
가 발생합니다.
1
console.log(a); // ReferenceError: a is not defined
반면에 var
로 선언한 변수는 변수 선언 부분과 초기화(undefined)가 호이스팅되므로 변수 선언 전에 접근하면 undefined가 반환됩니다.
1
2
3
console.log(a); // undefined
var a = 1;
console.log(a); // 1
위의 코드는 내부적으로 다음과 같이 동작합니다.
1
2
3
4
var a; // 변수 선언 호이스팅 (undefined로 초기화)
console.log(a); // undefined
a = 1; // 할당
console.log(a); // 1
let
과 const
변수 호이스팅
let
과 const
로 선언된 변수도 변수 선언 부분은 호이스팅되지만, 초기화는 실제 변수 선언 부분에서 이루어지므로 초기화 전에 접근하면 ReferenceError
가 발생합니다. 변수가 선언되고 초기화 단계에 접어들기 전까지의 구간을 TDZ(Temporal Dead Zone, 일시적 사각지대)
라고 부릅니다.
예를 들어 다음과 같이 초기화 전에 변수에 접근하면 ReferenceError
가 발생합니다.
1
2
console.log(a); // ReferenceError: Cannot access 'a' before initialization
let a = 1;
1
2
console.log(a); // ReferenceError: Cannot access 'a' before initialization
const a = 1;
함수 호이스팅
함수의 경우 함수 선언 방식에 따라 호이스팅 동작 방식이 다릅니다.
함수 선언문(Function Declaration)
함수 선언문(Function Declaration)
은 function 정의부만 존재하고 별도의 할당 명령이 없는 것을 의미하며, 함수 선언문
은 함수 전체가 호이스팅됩니다. 즉, 함수 선언과 동시에 메모리에 할당되므로, 코드 어디에서든 호출할 수 있습니다. 변수와 달리 함수는 초기화까지 호이스팅되는 이유는 function 키워드로 선언한 함수는 선언과 초기화, 할당 단계가 내부적으로 동시에 진행되기 때문입니다. 반면에 변수는 선언과 초기화를 한 구문으로 코딩하더라도 내부적으로는 두 단계에 걸쳐서 실행됩니다.
예를 들어 다음과 같이 함수가 선언되기 전에 호출할 수 있습니다.
1
2
3
4
5
sayHello(); // "Hello, world!"
function sayHello() {
console.log("Hello, world!");
}
위의 코드는 내부적으로 다음과 같이 동작합니다.
1
2
3
4
5
function sayHello() {
console.log("Hello, world!");
}
sayHello(); // "Hello, world!"
만약 다음과 같이 같은 이름의 함수 선언문을 여러 개 선언하는 경우 나중에 할당할 값이 먼저 할당한 값을 덮어씌우므로 가장 마지막에 선언한 함수가 호출됩니다.
1
2
3
4
5
6
7
8
9
console.log(b()); // "b2"
function b() {
return "b1";
}
function b() {
return "b2";
}
함수 표현식(Function Expression)
함수 표현식(Function Expression)
은 정의한 function을 별도의 변수에 할당하는 것을 의미하며, 함수 표현식
은 변수에 할당된 함수로 취급되므로, 변수 호이스팅 규칙을 따릅니다. 따라서 선언 전에 호출하려고 하면 오류가 발생합니다.
var
로 선언된 경우, undefined로 호이스팅되므로 TypeError
가 발생합니다.
1
2
3
4
5
sayHello(); // TypeError: sayHello is not a function
var sayHello = function () {
console.log("Hello, world!");
};
let
과 const
로 선언된 경우, TDZ
로 인해 ReferenceError
가 발생합니다.
1
2
3
4
5
sayHello(); // ReferenceError: Cannot access 'sayHello' before initialization
const sayHello = function () {
console.log("Hello, world!");
};
클래스 호이스팅
ES6에 도입된 class
의 경우, 클래스 선언은 호이스팅되지만, let
이나 const
처럼 초기화 전에 접근하면 ReferenceError
가 발생합니다. 따라서 class
는 함수와 다르게 선언 전에는 사용할 수 없습니다.
1
2
3
4
5
6
7
const person = new Person("HyunJinNo"); // ReferenceError: Cannot access 'Person' before initialization
class Person {
constructor(name) {
this.name = name;
}
}
import 호이스팅
import 선언은 항상 모듈의 최상단으로 호이스팅됩니다.
1
2
3
// test.js
export let a = 10;
1
2
3
console.log(a); // 10
import { a } from "./test.js";