[JavaScript] 호이스팅

Letmegooutside·2022년 1월 8일
0

JavaScript

목록 보기
5/25
post-thumbnail
post-custom-banner

호이스팅 (Hoisting)

코드를 실행하기 전 변수와 함수 선언이 파일의 맨 위로 끌어 올려진 것과 같은 현상

JS 엔진은 코드를 실행하기 전, 실행 가능한 코드를 형상화하고 구분하는 과정(실행 컨텍스트를 위한 과정)을 거치는데 이 과정에서 변수와 함수 선언을 메모리에 저장한다. 따라서 코드를 실행했을 때 메모리에 저장된 데이터가 이미 있으므로 선언이 호출보다 하단에 있어도 선언이 상단에 끌어올려진 것과 같이 동작(오류 없이 동작)하게 된다.

자바스크립트는 모든 선언문이 호이스팅 된다는 특징 때문에 모든 선언문이 선언되기 이전에 참조 가능하다.

* 실행 컨텍스트 : 실행 가능한 코드가 실행되기 위해 필요한 환경

변수 호이스팅

변수 선언 단계

  1. 선언단계
    변수 객체(Variable Object)에 변수를 등록한다. 이 변수는 객체 스코프가 참조하는 대상이 된다.

  2. 초기화 단계
    변수 객체(Variable Object)에 등록된 변수를 메모리에 할당한다. 이 단계에서 변수는 undefined로 초기화된다.

  3. 할당 단계
    undefined로 초기화된 변수에 실제 값을 할당한다.

var 키워드로 선언된 변수는 선언 단계와 초기화 단계가 한번에 이루어진다.
변수가 스코프에 등록되고, 변수는 메모리 공간을 확보한 후 undefined로 초기화 된다.
그 이후 변수 할당문에 도착하면 비로소 값의 할당이 이루어지는 것이다.

따라서 변수 선언문 이전에 변수에 접근하여도, 변수 객체에 변수가 undefined로 초기화 되어 존재하기 때문에 에러가 발생하지 않는데, 이러한 현상을 변수 호이스팅이라고 하는 것이다.

console.log(foo); // 1. undefined
var foo = 123;
console.log(foo); // 2. 123

위의 코드에서 1이 실행되기 전에 var foo=123이 호이스팅 되어 변수 객체에 등록되고 undefined로 초기화 된다. 따라서 foo를 출력하면 undefined가 출력이 된다.

두번째 행의 var foo=123이 실행되면서 undefined로 초기화 되어 있었던 foo 변수에 값이 할당되어 2에서는 123이 출력되게 된다.

let, const 키워드

let, const 키워드를 사용한 선언문은 호이스팅이 발생하지 않는 것처럼 동작한다.
var 키워드와 달리 let키워드로 선언된 변수를 선언문 이전에 참조하면 참조 에러가 발생한다.

TDZ (Temporal Dead Zone)

변수가 선언되고 초기화 되기까지의 범위

let 키워드로 선언된 변수는 var과 달리 선언단계와 초기화 단계가 나누어서 진행된다.
즉 선언 단계에서 스코프에 변수를 등록하지만 어떤 값으로도 초기화하지 않고 있다가, 변수 선언문에 도달했을 때(코드 실행 이후) 초기화가 이루어진다.

따라서 변수 선언문 이전에는 변수가 초기화 되지 않았기 때문에 변수를 위한 메모리 공간이 확보되지 않은 상태이므로 참조 에러가 발생하게 된다.

이 때, 변수를 참조할 수 없는 스코프의 시작 지점부터 초기화 시작 점까지의 구간을 TDZ라고 한다.

  • TDZ의 영향을 받는 구문
    : const, let, class, constructor() 내부의 super(), 기본값 매개변수

  • TDZ의 영향을 받지 않는 구문
    : var, 함수 선언식

let, const 변수는 초기화되지 않은 상태로 선언만 메모리에 저장되기 때문에 호이스팅이 발생하는 것은 맞다. 하지만 할당된 값이 없어 참조할 수 없기 때문에 호이스팅이 발생하지 않는 것처럼 동작하게 되는 것이다.

함수 호이스팅

함수 선언문

함수 선언문으로 정의된 함수는 선언과 초기화, 할당이 한 번에 이루어진다.
그렇기 때문에 함수의 선언 위치와는 상관없이 소스 내 어느 곳에서든 호출이 가능하다.

함수 표현식

함수 표현식의 경우 함수 선언문과 달리 런타임에 해석되고 실행되므로 호이스팅의 영향을 받지 않는다.

foo1(); // 함수 선언문에서는 호이스팅 일어난다. Hello 출력
foo2(); // 함수 표현식이라서 호이스팅 안된다. 타입 에러 발생 
console.log(foo2); // undefined
function foo1() {
  console.log('Hello');
}
var foo2 = function() {
  console.log('world');
}

위와 같은 경우 함수표현식으로 선언한 foo2()를 호출하면 타입에러가 발생하게 되는데, 이는 함수 자체가 호이스팅되지 않고 var foo2라는 변수가 undefined로 초기화되고 호이스팅 되었기 때문이다.

문제점

코드의 가독성과 유지보수를 위해 호이스팅은 지양하는 것이 좋다.

var n = 4;
function hoistingN() {
  console.log(n);	//undefined
  var n = 6;
  console.log(n);	//6
}
hoistingN();

호이스팅은 함수보다 변수에서 먼저 일어난다.
따라서 n이 먼저 호이스팅되어 변수가 undefined로 초기화된 상태에서 함수 호이스팅이 일어나 위와 같은 결과가 나오게 된다.

이렇듯 호이스팅은 코드 실행 결과를 예측하기 어렵게 만든다.
이를 해결하기 위해 나온 방법이 ES6의 letconst인 것이다.




Refernece
https://hanamon.kr/javascript-호이스팅이란-hoisting/
https://taenami.tistory.com/m/87
https://poiemaweb.com/js-data-type-variable
https://jae04099.tistory.com/entry/JavaScript-호이스팅hoisting-이란

post-custom-banner

0개의 댓글