By kimcoder
2018.09.17

TDZ(Temporal Dead Zone)

오늘은 TDZ, Temporal Dead Zone에 대해 글을 쓰고자 한다.
TDZ에 대해 알려면, 호이스팅과 let, const, scope 등에 대한 기본적인 이해가 있어야 한다.

Temporal Dead Zone

위에서 이야기한 것처럼 TDZ에 대해 알려면, 호이스팅, let & const에 대해 알아야 한다.

호이스팅

호이스팅은 인터프리터가 변수와 함수의 메모리 공간을 선언 전에 미리 할당하는 것을 의미한다.
var로 선언한 변수의 경우 호이스팅 시 undefined로 변수를 초기화하게 된다.

let & const

letconst는 ES5+부터 사용할 수 있고 block scope 기반으로 동작하는 변수타입이다.
아래 코드를 보자.

console.log(x); // undefined
console.log(y); // ReferenceError

var x = 'x';
let y = 'y';

변수의 선언부는 해당 scope의 최상단으로 끌어올려져 해석된다.
하지만 위의 코드에서 let으로 선언한 변수 y에 접근시에는 ReferenceError를 내뱉는다.

그럼 let은 호이스팅이 되지 않는 것인가?
그렇지 않다. letconst도 마찬가지로 호이스팅되지만, 변수의 초기화가 실행되지 않는다.

위의 코드에서 let변수에 접근이 불가능한 이유가 바로 TDZ때문이다.
MDN문서의 내용을 참고하자면, 아래와 같이 한마디로 정의할 수 있다.
letconst는 블록의 시작부터 초기화가 실행되기전까지 TDZ에 존재하게 된다는 것.
따라서, TDZ에 존재하면 위와 같이 접근을 할 수 없다.

Temporal

DeadZone 형성이 시간상(Temporal)인 이유는 이유는
사각지대가 코드의 작성 순서(위치)가 아니라 코드의 실행 순서(시간)에 의해 형성되기 때문이다.

{
  // TDZ가 스코프 맨 위에서부터 시작
  const func = () => console.log(letVar); // OK

  // TDZ 안에서 letVar에 접근하면 ReferenceError

  let letVar = 3; // letVar의 TDZ 종료
  func(); // TDZ 밖에서 호출함
}

위 코드의 경우 let 변수 선언 코드가 그 변수에 접근하는 함수보다 아래에 위치하지만, 함수의 호출 시점이 사각지대 밖이므로 정상 동작한다.

여러가지 상황들

TDZ with Lexical Scope

function test() {
  var foo = 33;
  if (true) {
    let foo = foo + 55; // ReferenceError
    console.log(foo);
  }
}
test();

MDN에 있는 예제 소스이다.
함수 내부의 조건문 block의 소스에서, foo 참조시 TDZ로 인한 ReferenceError가 발생한다.
foo의 초기화 구문에서 (foo + 55)의 foo가 TDZ에 있기(아직 초기화가 되지 않았기) 때문이다.

TDZ with Default Function Parameter

(function (a = b, b) {})(undefined, 1); // ReferenceError
(function (a = a) {})(); // ReferenceError

위의 2가지 예제들도 똑같이 에러가 발생한다.
함수의 디폴트 파라미터가 TDZ에 있는(초기화실행이 되지 않은 상태의) 값을 참조하고 있기 때문이다.
위의 경우에선, a가 b를 참조하는데, b의 초기화가 아직 되지 않은 상태이다.
(디폴트 파라미터는 왼쪽에서 오른쪽으로 실행)
아래에선, 위의 foo 예제와 같은 케이스이다. a의 초기화 구문에서 접근하려는 a가 TDZ에 있기 때문이다.

마치며

var로 변수를 선언하고 사용할 때도 마찬가지이지만, 초기화 후 사용에 대한 안전한 방식의 코딩스타일을 지향하는 것이 좋다.
확실한 것은, letconst를 사용하고 TDZ에 대한 개념을 잘 알고 있다면, 여러 부작용을 방지할 수 있을것이다.

References