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

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

호이스팅이란?

JavaScript에서 호이스팅(hoisting)이란, 인터프리터변수와 함수의 메모리 공간을 선언 전에 미리 할당하는 것을 의미합니다. var로 선언한 변수의 경우 호이스팅 시 undefined로 변수를 초기화합니다. 반면 let과 const로 선언한 변수의 경우 호이스팅 시 변수를 초기화하지 않습니다.

호이스팅을 설명할 땐 주로 "변수의 선언과 초기화를 분리한 후, 선언만 코드의 최상단으로 옮기는" 것으로 말하곤 합니다. 따라서 변수를 정의하는 코드보다 사용하는 코드가 앞서 등장할 수 있습니다. 다만 선언과 초기화를 함께 수행하는 경우, 선언 코드까지 실행해야 변수가 초기화된 상태가 됨을 주의하세요.

출처 : mdn web docs

호이스팅 대상

  1. 변수
  2. 함수

다음의 코드를 보면 호이스팅 대상에 대한 감을 잡을 수 있다.

// 예제 1
// y만 호이스팅 대상

x = 1; // x 초기화. x를 선언하지 않은 경우 선언. 그러나 명령문에 var가 없으므로 호이스팅이 발생하지 않음
console.log(x + " " + y); // '1 undefined'
// JavaScript는 선언만 호이스팅하므로, 윗줄의 y는 undefined
var y = 2; // y를 선언하고 초기화

// 예제 2
// 호이스팅은 없지만, 변수 초기화는 (아직 하지 않은 경우) 변수 선언까지 병행하므로 변수를 사용할 수 있음

a = '크랜'; // a 초기화
b = '베리'; // b 초기화

console.log(a + "" + b); // '크랜베리'
  • var 없이 선언&초기화를 하는 경우 = 호이스팅 대상 아님
  • var 선언&초기화를 하는 경우 = var y가 호이스팅 대상임, = 2는 대상이 아님
  • 오직 var 로 선언한 변수만이 호이스팅의 대상임
  • 호이스팅의 대상이 되지 않았지만 예제 2의 경우 런타임에서 정상적으로 선언&초기화가 이뤄져서 인터프리터가 정상적으로 처리하여 참조값이 잘 표시됨.

1. 변수 호이스팅 var 와 let/const

다음 코드를 보면 각각 어떻게 동작하는지 알 수 있다.

####var

//사용자가 작성한 코드
console.log(a);
var a = "안녕하세요";
console.log(a);
//호이스팅이 동작한 코드
var a; // 선언&초기화 (undefined)
console.log(a); //
a = "안녕하세요";
console.log(a);

실행 결과 undefined “안녕하세요”

이처럼 값을 할당하기 위해서 작성한 var a = "안녕하세요"에서 선언 부분인 var a만을 호이스팅 대상으로 보고 호이스팅 한 후, undefined로 초기화 한다. 후에 코드를 순차적으로 실행하는 런타임에서 값을 할당하여 다음 log에서는 안녕하세요로 출력이 된 것을 볼 수 있다.

위의 경우는 var의 경우이고 constlet의 경우는 다르다.

let/const

//사용자가 작성한 코드
console.log(a);
let a = "안녕하세요";  //const도 동일
console.log(a);
//호이스팅이 동작한 코드
let a; // 선언
console.log(a); //초기화되지 않아 Runtime ERROR 발생
a = "안녕하세요";
console.log(a);

var와 다르게 인터프리터에서 선언만 할 뿐, 호스팅을 진행하지 않아서 첫 번째 log 출력에서 undefined를 출력하지 않고 ERRO0R가 발생한다.

var와 let/const의 호이스팅 차이

var

var 로 선언하여 Hoisting 대상이 되는 경우, 변수를 undefined로 초기화한다.

let과 const

letconst로 선언하여 Hoisting 대상이 되는 경우, 따로 변수를 초기화하지 않는다.

정리

var로 선언하여 호이스팅 된 변수에는 자동으로 undefined로 초기화 되기 때문에 별도로 초기화하지 않은 채로 참조를 해도 인터프리터 단에서 ERROR 를 발생시키지 않으나, letconst로 선언하여 호이스팅 된 변수는 초기화 되지 않았기 때문에 이 상태에서 참조할 경우 인터프리터에서 다음과 같은 에러를 출력한다. // Uncaught SyntaxError: Identifier 'name' has already been declared

좀더 상세히는 constlet 는 var와 다르게 선언과 초기화가 다른 단계에서 동작한다. var는 실행 컨텍스트 Execution pahse(실행단계에서)선언과 초기화가 동시에 이뤄지는 반면, constlet의 경우 선언은 마찬가지로 진행되고, 초기화는 런타임에 발생한다.

2. 함수 선언문 호이스팅

함수 선언문과 함수 표현식의 차이

함수 선언문은 변수와 마찬가지로 호이스팅의 대상이된다. 따라서 다음 코드는 정상적으로 안녕하세요를 출력한다.

onClick();

function onClick(){
    console.log('안녕하세요');
}

호이스팅 우선순위

1순위 : 변수 2순위 : 함수 선언문

//사용자가 작성한 코드

var a = "안녕";

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

var b = "하세요";

console.log(typeof a);
console.log(typeof b);
//호이스팅이 동작한 코드

//1. 변수 호이스팅
var a;
var b;

//2. 함수 선언문 호이스팅
function a() {
    console.log("hi");
}
function b() {
    console.log("hello");
}

a = "안녕";
b = "하세요";

console.log(typeof a); // string
console.log(typeof b); // string

여기서 a, b 값 할당이 없다면?

// 사용자가 작성한 코드

var a;

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

var b;

console.log(typeof a);
console.log(typeof b);
//호이스팅이 동작한 코드

//1. 변수 호이스팅
var a;
var b;

//2. 함수 호이스팅
function a() {          //a가 함수로 초기화
    console.log("hi");
}
function b() {          //b가 함수로 초기화
    console.log("hello");
}


console.log(typeof a);
console.log(typeof b);

3. 함수 표현식 호이스팅

함수 표현식의 호이스팅의 경우는 다음과 같다. 호이스팅의 영향을 받아 프로그램이 꼬일 여지가 많아보인다.

//사용자가 작성한 코드
a();

var a = function () {
  console.log("안녕하세요");
}
//호이스팅이 동작한 코드

//변수 호이스팅
var a; // undefined

a(); // not function ERROR

a = function () {
  console.log("안녕하세요");
}

정리

호이스팅의 의도를 잘 알고 잘 쓰는 것이 필요하다는 생각이 든다. 또한 var을 지금은 사용하지 않는 것을 권장하지만 오래된 코드를 만질 일이 분명히 있고 호환성 때문에 이를 고려해야할 것인데, 동작원리를 알게 되어 var를 쓰지 말아야하는 이유를 파악할 수 있었다. 앞으로 이 부분에 대해서 인지하는 습관을 가져야겠다.


변수 용어정리

  1. 선언 단계 : 변수 이름을 실행 컨텍스트에 등록해서 자바스크립트 엔진에 변수 사용을 알림
  2. 초기화 단계 : 값을 저장하기 위한 메모리 공간을 확보하고, undefined를 할당하여 초기화함 (이처럼 초기화 하는 이유는 연결된 확보한 메모리공간에 쓰레기 값이 남아있을 수 있기 때문이라고)
  3. 할당 단계 : 소스코드가 순차적으로 실행되는 시점인 런타임에 실행되며 주소 공간에 값 저장한다.

© 2021. All rights reserved.