본문 바로가기

Study/JavaScript

[JavaScript] 호이스팅이란?

호이스팅이란 코드를 실행하기 전에, 변수 선언/ 함수 선언에 대한 메모리 공간을 미리 할당해 두는 것을 말한다.

 

변수 선언/ 함수 선언런타임 이전에 먼저 실행되는데, 

변수 선언/ 함수 선언코드의 선두로 올려진것 처럼 동작하는 자바스크립트 고유의 특징이다.


#1. 변수 호이스팅

-  변수 선언시, 변수 선언문이 코드의 선두로 끌어올려진 것처럼 동작하는데 이를 함수 호이스팅이라고 한다.

- var, let, const 모든 키워드로 선언 시, 변수 호이스팅은 발생하지만, 각각의 출력 형태는 약간 상이하다.

 

1. var로 변수 선언시 ... > undifined로 초기화.

- var 키워드로 선언한 변수는 런타임 이전에 변수 호이스팅에 의해 선언되고, undifined 값으로 초기화가 진행된다.

console.log(score);  // undefined

var score;           // 1. 변수 선언
score = 80;          // 2. 값의 할당

console.log(score);  // 80

 

2. let, const 로 선언시 ... > 변수를 초기화 하지 않음 

- let, const 키워드로 선언한 변수는 변수 호이스팅이 발생하지 않는 것처럼 동작한다. (하지만 값이 undifined로 초기화 되지 않을 뿐, 호이스팅은 발생하긴 한다.)

 

1) let

- let 키워드로 선언한 변수는 '선언단계' 와 '초기화 단계'가 분리되어 진행된다.

런타임 이전에 자바스크립트 엔진에 의해 암묵적으로 선언단계가 먼저 실행되지만, 초기화 단계는 변수 선언문에 도달했을 때 실행된다. 

- 만약 초기화 단계가 실행되기 이전에 변수에 접근하려고 하면 참조에러가 발생한다.

- 스코프의 시작지점부터 초기화 시작 지점까지 변수를 참조할 수 없는 구간을 일시적 사각지대 라고 부른다.

// 런타임 이전에 선언 단계가 실행된다. 아직 변수가 초기화 안됌
// 초기화 이전의 일시적 사각지대에서는 변수를 참조할 수 없다.
console.log(foo);   // 결과 : caught ReferenceError: foo is not defined 에러남

let foo;           // 1. 변수 선언
console.log(foo);  // 결과 : undifined
foo = 1;           // 2. 값의 할당
console.log(foo)   // 결과 : 1

 

2) const

- const 또한 호이스팅이 발생하지 않는것 처럼 동작한다.

console.log(foo2);
const foo2 = 5;       // 결과 : foo2 is not defined

 

 


#2. 함수 호이스팅

- 함수 또한, 함수 선언문이 코드의 선두로 끌어올려진 것처럼 동작하는데,

함수 호이스팅은 함수를 함수 선언문(function 함수명()) 으로 정의할때 발생한다.

만약, 함수를 함수 표현식(var 변수명 = function함수명()) 으로 정의 했다면, 이때는 변수 호이스팅이 발생한다.

 

1. 함수 선언문으로 함수를 정의하면 ... > 함수 호이스팅 발생

① 런타임 이전에 함수 객체가 먼저 생성

② 자바스크립트 엔진은 함수 이름과 동일한 이름의 식별자를 암묵적으로 생성

③ 생성된 함수 객체를 생성한다.

- 따라서 함수 선언문 이전에 함수를 참조할 수 있으며 호출할 수도 있다.

- 이처럼 함수 선언문이 코드의 선두로 끌어올려진 것처럼 동작하는 자바스크립트의 고유의 특징을 함수 호이스팅이라고 한다. 

catName("클로이");

function catName(name) {
  console.log("제 고양이의 이름은 " + name + "입니다");
}

// 결과 : 제 고양이의 이름은 클로이입니다

 

2. 함수 표현식으로 함수를 정의하면 ...> 변수 호이스팅 발생

① var 키워드로 선언된 변수는 undifined로 초기화

② var 키워드를 사용한 변수 선언문 이전에 변수를 참조하면 변수 호이스팅에 의해 undifined로 평가.

 

- 변수 할당문의 값은 할당문이 실행되는 시점, 즉 런타임에 평가되므로 함수 표현식의 함수 리터럴 할당문이 실행되는 시점에 평가되어 함수 객체가 된다.

-  따라서 함수 표현식으로 함수를 정의하면 함수 호이스팅이 발생하는 것이 아니라 변수 호이스팅이 발생한다.

 

- 아래와 같이 정의하면 잘 작동하는 실행문이

var catFunc2 = function catName(name) {
  console.log("제 고양이의 이름은 " + name + "입니다");
}

catFunc2("나비")

// 결과 : caught TypeError: catFunc2 is not a function 에러남

 

- 함수 호이스팅을 생각하며, 아래와같이 정의하면 의도대로 동작하지 않으므로! 꼭 함수 표현식으로 정의한 함수는 반드시 함수 표현식 이후에 참조 또는 호출해야한다. 

catFunc2("나비")

var catFunc2 = function catName(name) {
  console.log("제 고양이의 이름은 " + name + "입니다");
}


// 결과 : caught TypeError: catFunc2 is not a function 에러남

 

한편, 함수 호이스팅은 함수를 호출하기 전에 반드시 선언해야한다는 당연한 규칙을 무시한다.

이 같은 문제때문에 json창안자 더글라스 크락포드는 함수 표현식을 사용을 권장한다.


* 참고자료

https://developer.mozilla.org/ko/docs/Glossary/Hoisting

이웅모. 모던 자바스크립트 Deep Dive』. 위키북스, 2020