[JavaScript] 변수와 함수 호이스팅(Hoisting)에 대해 알아보자

IN DUCK KANG·2021년 6월 25일
13
post-custom-banner

호이스팅이란 무엇일까?

  • 사전적 정의 : 끌어 올리기

호이스팅(Hoisting)이란 함수 내의 변수 및 함수 선언을 각 유효 범위의 최상단으로 끌어 올려주는 JS의 독특한 특징이다.

실제로 코드가 끌어올려지는 것은 아니고, 자바스크립트 parser가 내부적으로 끌어올려서 처리한다.

컴파일 단계에서 코드 실행 전 함수와 변수 선언을 스캔하고, 모든 함수와 변수 선언들은 렉시컬 환경이라 불리는 자바스크립트 데이터 구조 내의 메모리에 추가된다.

console.log(a); // undefined
var a = "A"; // var 변수 
/* 호이스팅 된 코드 */
var a; 
console.log(a);
a = "A";

var a를 상단으로 호이스팅했기 때문에 변수 선언 전에 console.log로 출력을 해도 에러가 발생하지 않고, undefined 가 출력된다.

모든 선언(function, var, let, const, class)은 JavaScript에서 호이스팅되며, var 선언은 undefined로 초기화되지만 let 및 const 선언은 초기화되지 않은 Temporal Dead Zone 상태로 유지된다.

자바스크립트의 변수 생성 단계

자바스크립트에서는 총 3단계에 걸쳐서 변수를 생성한다.

  • 선언(Declaration): 스코프와 변수 객체가 생성되고, 스코프가 변수 객체를 참조한다. 초기화 전까지는 TDZ 상태이다.
  • 초기화(Initialization): 변수 객체 값을 위한 공간을 메모리에 할당한다. 이 때 할당되는 값은 undefined다. myValue = undefined
  • 할당(Assignment): 변수 객체에 값을 할당한다. myValue = 150

렉시컬 환경

// 선언
lexicalEnvironment = {
  a: <uninitialized>
}
// 초기화
lexicalEnvironment = {
  a: undefined
}
// 할당
lexicalEnvironment = {
  a: 10
}

var, let, const

var는 선언과 동시에 초기화가 이루어진다. 즉, 선언과 동시에 undefined가 할당된다.

그러나 letconst는 다르다. 선언만 될뿐, 초기화가 이루어지지 않는 메모리 할당이 아직 되지 않은 TDZ에 들어가게 된다.

모든 선언(function, var, let, const 및 class)은 JavaScript에서 호이스팅되며, var 선언은 undefined로 초기화되지만 let 및 const 선언은 초기화되지 않은 상태로 유지된다.

undefined vs ReferenceError

console.log(hoist); // Output: undefined
var hoist = 'The variable has been hoisted.';
console.log(hoist); // Output: ReferenceError: hoist is not defined ...
let hoist = 'The variable has been hoisted.';

let, const 도 호이스팅이 될까?

var hoist = "AA";

(function func() {
  console.log(hoist); // Output: ReferenceError
  let hoist = "BB";
})();

만약 let과 const가 호이스팅이 되지 않는다면 console.log(hoist) 에 'AA' 가 출력되어야 하는데 ReferenceError 가 발생한다. 즉 let과 const도 호이스팅된다.

함수 선언식 (Function declarations)

함수 선언식은 호이스팅 된다.

hoisted(); // Output: "This function has been hoisted."

function hoisted() {
  console.log('This function has been hoisted.');
};

함수 표현식 (Function expressions)

함수 표현식은 호이스팅 되지 않는다.

expression(); //Output: "TypeError: expression is not a function

var expression = function() {
  console.log('Will this work?');
};

함수 표현식과 함수 선언식을 조합하여도 마찬가지로 호이스팅 되지 않는다.

expression(); // Ouput: TypeError: expression is not a function

var expression = function hoisting() {
  console.log('Will this work?');
};

Class 선언식 (declarations)

자바스크립트의 class 선언식은 호이스팅이 되고, 초기화하지 않은 'TDZ' 상태로 유지된다. 따라서 class에 접근하기 위해서는, 먼저 선언을 해야만한다.

var Frodo = new Hobbit();
Frodo.height = 100;
console.log(Frodo); // Output: ReferenceError: Hobbit is not defined

class Hobbit {
  constructor(height) {
    this.height = height;
  }
}

Class 표현식 (expressions)

함수 표현식처럼, class 표현식은 호이스팅되지 않는다.

var Square = new Polygon();
Square.height = 10;
console.log(Square); // Output: TypeError: Polygon is not a constructor

var Polygon = class Polygon {
  constructor(height) {
    this.height = height;
  }
};

결론

호이스팅은 함수를 어디에 선언 하였든지, 신경 쓰지 않고 필요한 곳에서 자유롭게 사용하기 위해 만들어진 기능이다. 그러나 이 기능이 때로는 의도치 않은 버그를 생성할 여지가 있다. 따라서 호이스팅을 의도적으로 사용하는 경우가 아니라면 호이스팅이 되지 않거나, Temporal Dead Zone 으로 초기화 되는 let, const, 함수 표현식을 사용하는 것을 권장한다.

profile
Web FE Developer
post-custom-banner

0개의 댓글