본문 바로가기

Javascript

자바스크립트 Hoisting

반응형

호이스팅

자바스크립트에서 호이스팅이란 유효 범위 내 최상단으로 변수와 함수를 끌어올리는 것을 말한다. 함수나 변수가 실제 선언은 밑에 되어있지만 호이스팅을 통해 유효 범위의 내 제일 위에 선언된 것 처럼 보이는 것이다.

호이스팅 대상

  • var로 선언된 변수
    • var로 선언된 변수의 선언만 호이스팅된다. 할당은 호이스팅되지 않는다.
    • let, const로 선언된 변수는 호이스팅되지 않는다.
console.log("hello");

var name = "var Ella"; // var 변수 
let name2 = "let Ella"; // let 변수

 

// 호이스팅 결과

var name;

console.log("hello");

name = "var Ella"; // var 변수 -> 호이스팅 발생
let name2 = "let Ella"; // let 변수 -> 호이스팅 발생 X

 

  • 함수 선언문
    • 함수 표현식은 호이스팅되지 않는다. 더 정확히 말하자면 var로 표현된 경우에는 선언부만 호이스팅된다. 하지만 변수 호이스팅과 같이 할당은 되지 않는다. 따라서 변수에 어떤 값이 들어갈지(숫자, 문자열, 함수 등) 모르므로 에러가 나온다.
func1();
func2();

function func1() { // 함수선언문
  console.log("function1");
}

var func2 = function() { // 함수표현식
  console.log("function2");
}

 

// 호이스팅 결과

var func2;

function func1() { // 함수선언문
  console.log("function1");
}

func1(); // function1
func2(); // Error

func2 = function() { // 함수표현식
  console.log("function2");
}

그런데 사실...

위에서 let과 const 로 선언된 변수는 호이스팅되지 않는다고 했다. 하지만 엄밀히 말하면 let과 const도 호이스팅된다. 다만 호이스팅되지 않은 것처럼 동작할 뿐이다. 아래의 예제를 보자.

 

let test = 1;

{
	console.log(test); //ReferenceError: Cannot access 'test' before initialization
	let test = 2;
}

 

만약 let으로 선언된 변수가 호이스팅되지 않는다면, 콘솔에는 1(전역변수)이 찍혀야한다. 하지만 호이스팅되기 때문에 초기화 전에 접근했다며 참조 에러가 나온다. 이를 이해하기 위해서는 변수 선언, 할당 과정을 좀 더 자세히 이해해야 한다.

var로 변수가 선언되는 과정

  1. 선언 단계 + 초기화 단계
  2. 할당 단계

var로 변수를 선언하면 런타임 이전에 자바스크립트 엔진에 의해 암묵적으로 선언, 초기화 단계가 한번에 진행된다. 즉, 선언 단계에서 스코프에 변수 식별자를 등록해서 자바스크립트 엔진에게 변수의 존재를 알리고, 즉시 undefined로 초기화한다.

따라서, 할당 이전에 변수에 접근해서 undefined가 나오지 에러를 반환하지는 않는다.

let, const로 변수가 선언되는 과정

  1. 선언 단계(TDZ)
  2. 초기화 단계
  3. 할당 단계

반면 let(or const)으로 선언되는 변수는 선언 단계과 초기화 단계가 분리되어 진행된다. 따라서 런타임 이전에 자바스크립트에 의해 암묵적으로 오로지 선언만 된다. 초기화 단계는 변수 선언문에 도달했을 때 실행된다. var과 다르게 변수 선언문 이전에 undefined로 초기화되지 않는다.

따라서, 초기화 단계가 진행이 안된 상태에서 해당 변수에 접근하면 참조에러(ReerenceError)가 발생한다. 이처럼 let으로 선언한 변수의 선언 단계부터 초기화 단계(변수 선언문)까지는 변수를 참조할 수 없고 이러한 구간을 일시적 사각 지대(Temporal Dead Zone: TDZ)이라 부른다.

정리해보자면, let, const, var로 선언된 변수 모두 호이스팅된다. 하지만 초기화 단계 시점의 차이가 있기 때문에 사용 가능 여부가 다르고, 이를 보고 우리는 let, const는 호이스팅 안된다고 생각하는 것이다.

호이스팅의 우선순위

  • 변수 선언이 함수 선언보다 위로 끌어올려진다.
var name = "variable name";

function name() { // 같은 이름의 함수 선언
	console.log('function name');
}

console.log(typeof name); // string

 

  • 값이 할당되지 않은 변수의 경우, 함수선언문이 변수를 덮어쓴다.
var name; // 값 할당 X

function name() { // 같은 이름의 함수 선언
    console.log('function name');
}

console.log(typeof name); // "function"

 

 

출처

https://gmlwjd9405.github.io/2019/04/22/javascript-hoisting.html

모던자바스크립트 Deep Dive 15장 let, const 키워드와 블록 레벨 스코프

반응형

'Javascript' 카테고리의 다른 글

자바스크립트 Shallow Copy vs Deep Copy  (0) 2021.10.02
자바스크립트 Strict mode  (1) 2021.09.24
자바스크립트 Prototype  (0) 2021.09.19
함수 선언문 vs 함수 표현식  (0) 2021.04.27
DOM  (0) 2021.04.27