JavaScript 호이스팅과 TDZ

손윤주·2022년 5월 20일
2
post-thumbnail

✔️ JavaScript 엔진에 대해 이해하고 가요

자바스크립트 엔진은 변수를 3단계로 나눠서 인지한다.
변수선언 3단계는 선언단계, 초기화단계, 할당단계로 이루어진다.

📍선언단계

(var, let, const) 로 변수를 선언하는 단계, 야 이거 변수야! 라고 엔진한테 알려주는 것

📍초기화단계

자바스크립트 엔진은 그 코드가 마치 전체 코드의 선두인것처럼 끌어올려 그 값을 저장할 메모리 공간을 따로 확보한다.
이를 변수 호이스팅이라 한다. var 의 경우 선언 시 초기화단계를 암묵적으로 undefined 로 실행하고 letconst 는 변수만 저장해놓고 선언하기 전까지 아래에 나올 개념인 TDZ에 넣어둔다.

📍할당단계

할당단계는 앞에서 선언했던 변수에 값을 할당하는 단계이며 선언과 할당을 한 줄로 할 수 있다. 한 줄로 할 경우 초기화된 공간에 메모리를 넣는 것이 아니라 초기화된 공간을 없애고 새로운 공간에 메모리를 넣는다고 함. 더이상 메모리를 사용할 필요가 없으면 Null을 할당한다.

참고자료


✔️ 호이스팅(hoisting)

JavaScript에서 호이스팅(hoisting)이란, 인터프리터가 변수와 함수의 메모리 공간을 선언 전에 미리 할당하는 것을 의미한다.

💡 호이스팅은 자바스크립트 엔진이 작업 실행 전에 변수와 함수만 골라 따로 모아두는 것!

var로 선언한 변수의 경우 호이스팅 시 undefined로 변수를 초기화하는 반면 letconst로 선언한 변수의 경우 호이스팅 시 변수를 초기화하지 않고 선언만 가져간다.
var는 재선언 남발이 가능해서 암묵적으로 초기화해놓는 것이다.

호이스팅을 구체적으로 나눠서 표현하자면, var 는 "선언과 초기화를 세트"로 가져가고, letconst는 "변수의 선언과 초기화를 분리한 후, 선언만 코드의 최상단으로 옮기는 것"이다. 따라서 변수를 정의하는 코드보다 변수를 사용하는 코드가 먼저 등장할 수 있다. 다만 선언과 초기화를 함께 수행하는 경우, 선언 코드까지 실행해야 변수가 초기화된 상태가 됨!

💡 변수랑 함수를 먼저 따로 모아놨다가 변수를 사용하는 코드가 나타나면 변수 선언이 앞 줄에 있든 뒷 줄에 있든 상관없이 변수를 꺼내서 적용해준다. 선언 전에 변수를 사용할 경우varundefined 를 꺼내고 나머지는 ReferenceError가 뜬다.

JS 엔진 : 나중에 값이 어떻게 할당될지 아직 모르겠고, 일단 젤 첨에 변수 선언한 애들 모아놓을게!

var 선언 시에는 undefined 뜸.

console.log(num); // 호이스팅한 var 선언으로 인해 undefined 출력
var num; // 선언
num = 6; // 초기화

다음 예제는 선언 없이 초기화만 존재하기 때문에 호이스팅에서 제외되고, 변수를 읽으려고 하면 에러가 뜸.

console.log(num); // ReferenceError
num = 6; // 초기화

아래 코드를 살펴보자.

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

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

// 예제 2
// 호이스팅은 없지만, 변수를 사용할 수 있음

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

console.log(a + "" + b); // '크랜베리'

💡 letconst 호이스팅
let과 const로 선언한 변수도 호이스팅 대상이지만, var와 달리 호이스팅 시 undefined로 변수를 초기화하지는 않습니다. 따라서 변수의 초기화를 수행하기 전에 읽는 코드가 먼저 나타나면 ReferenceError가 발생합니다.


✔️ TDZ (Temporal Dead Zone)

TDZ은 let, const, class 구문의 유효성을 관리한다.
자바스크립트에서 변수가 동작하는 방식을 이해하는 것은 매우 중요하다.

let, const, classvar 와 다르게 선언단계와 초기화 단계가 분리되어 있기 때문에
선언하기 전에 변수를 호출하면 참조 에러(ReferenceError)가 발생한다.

변수를 호이스팅은 하지만, 실제로 선언하는 코드가 나타나기 전까지 내보내지는 않는 것!
TDZ는 변수가 호이스팅되어 선언되기 전까지 머무는 사각지대 라고 이해하면 쉽다.

참고로 function함수는 변수선언 3단계를 동시에 진행해버린다.


1. const

const 먼저 살펴보자.

const white = '#FFFFFF'; // 변수를 선언하고나서

white; // => '#FFFFFF' // 초기화하면 변수에 접근할 수 있다. (정상동작)

이번에는 선언 전에 변수를 부르면 어떻게 되는지 보자.

white; // throws `ReferenceError`
const white = '#FFFFFF';

white

💡 이 때 const white = '#FFFFFF' 구문 전까지, white 변수는 TDZ에 있다!

TDZ에 있는 white 변수에 접근하게 되면 , ReferenceError: Cannot access 'white' before initialization 자바스크립트 에러가 발생한다.


2. let

letconst 와 마찬가지다.

// Does not work!
count; // throws `ReferenceError`
let count;

count = 10;

선언 이후에 사용해야 한다.

let count;

// Works!
count; // => undefined
count = 10;

// Works!
count; // => 10

3. class

class 또한 선언 전에는 사용할 수 없다.

// Does not work!
const myNissan = new Car('red'); // throws `ReferenceError`

class Car {
  constructor(color) {
    this.color = color;
  }
}

이렇게 써야 정상작동!

class Car {
  constructor(color) {
    this.color = color;
  }
}

// Works!
const myNissan = new Car('red');
myNissan.color; // => 'red'

함수 선언문과 함수 표현식에서 호이스팅 방식의 차이

//함수 선언문
function getName() { 
    console.log('name');
}

//함수 표현식
var name = function() { 
   console.log('name');
};

javascript 에서는 함수를 변수에 담을 수 있다. 이렇게 사용하는 것을 함수 표현식 이라고 한다.
그리고 function getName() 과 같이 함수를 선언하는 것을 함수 선언문 이라고 한다.

그렇다면 함수 표현식과 함수 선언문 둘다 함수이지만 호이스팅에 차이가 있다.


차이점

  • 함수 선언문 은 해당 함수 전체 내용을 호이스팅한다. (var 초깃값 undefined 세트로 저장하는 것처럼)
  • 함수 표현식 은 선언만 저장하고 값은 호이스팅하지 않는다. (let 또는 const 처럼)

호이스팅 규칙

부등호가 큰 쪽이 먼저 인식된다

변수 선언 > 함수 선언
할당되어있는 변수 > 할당되지 않은 변수


참고자료 출처 - hyun-jii.log
참고자료 출처2 - ui.toast.com
참고자료 출처3 - developer.mozilla.org

0개의 댓글