코딩 공부 일지/JavaScript

TDZ를 아시나요? - 에러 기록

헬로코딩 2022. 3. 28. 20:45
728x90

오늘은 대망의 첫 면접을 봤다.

면접관들의 질문에 어찌저찌 잘 대답을 하고, 드디어 코딩테스트!! 두둥!!!

 

리액트로 구현하는 문제였는데, 1에서 25까지 숫자를 5X5 빙고 배열에 랜덤으로 출력하고 랜덤 버튼을 누를 때 마다 다시 랜덤으로 숫자 위치가 바뀌는 것을 구현하는 것이었다. 

 

나는 랜덤 배열을 구성하기 위해 아래와 같은 코드를 작성했다.

function randomBingo() {
    let index = bingoEl.length - 1
    while(index > 0) {
      const randomIndex = Math.floor(Math.random() * bingoEl.length)
      [bingoEl[index], bingoEl[randomIndex]] = [bingoEl[randomIndex], bingoEl[index]]
      index--
    }
    return bingoEl
  }

그런데 아래와 같은 에러가 났다.

 

바로 구글링을 하고 싶은 마음이 굴뚝 같았다ㅠㅠ 그런데 시험에서 구글링을 하면 안 될 것 같아서 이유도 모르는 에러를 가지고 낑낑대다가 결국 풀지 못했다.

그리고 집에 와서 검색해보니... TDZ 문제라는 것을 알았다.

TDZ 란?

TDZ는 'Temporal Dead Zone'의 약자로 변수가 선언되기 전에 변수에 접근할 때 (var는 해당 안 됨, 호이스팅이 일어나니까) 변수에 접근하지 못하도록 금지하는 규칙이다.

 

예를 들어, 아래와 같은 코드가 있다고 가정하자.

console.log(fruit)
const fruit = 'strawberry'
const fruit = 'strawberry'
console.log(fruit)

첫번째 코드에서는 console.log가 변수 선언 전에, 두번째 코드는 변수 선언 후에 실행되도록 만들었다. 첫번째 코드를 실행하면 아래와 같은 에러가 뜬다.

두번째 코드는 정상 작동한다.

첫번째 코드에서는 변수가 선언되기 전에 변수에 접근했기 때문이다. 이 때 변수가 선언되기 이전의 공간을 TDZ라고 한다. 변수가 선언되기 전에는 변수에 접근할 수 없다. 이러한 경우는 let과 const로 변수를 선언하거나 Class형 객체를 선언할 때 일어난다. (함수선언문은 해당 안 됨, 마찬가지로 호이스팅이 일어나기 때문에!)

 

그렇다면, 다시 나의 코드로 돌아가보자.

function randomBingo() {
    let index = bingoEl.length - 1
    while(index > 0) {
      const randomIndex = Math.floor(Math.random() * bingoEl.length)
      [bingoEl[index], bingoEl[randomIndex]] = [bingoEl[randomIndex], bingoEl[index]]
      index--
    }
    return bingoEl
  }

내 코드를 보면 전혀 문제될 것이 없어보인다. 모두 선언 이후에 변수에 접근했다.

그러나 한 가지 간과한 사실이 있었다. randomIndex 선언 이후 구조분해할당으로 배열을 바꿀 때 배열만 코드에 이루어져 있으니 코드를 구분하기가 어려웠던 것이다. 다시 말하면, const randomIndex를 선언하는 줄 마지막에 세미 콜론을 찍어주니 오류가 사라졌다.... randomIndex를 선언하는 것을 끝내지 않은 것으로 해석이 된 것 같았다. 그래서 randomIndex 변수에 접근을 할 수가 없었던 것이다.

 

하아... 세미콜론을 잘 찍자....

 

아무튼 계속해서 TDZ에 대해 알아보자.

TDZ의 여러 예시

1. const, let 변수

console.log(fruit); // 변수 선언 이전에 접근할 경우 TDZ에 속하므로 에러를 일으킨다.
const fruit = 'strawberry';

console.log(num); // let 도 마찬가지다.
let num = 2;

2. Class 구문

const sally = new Student('sally') // 클래스 선언 전에 새로운 인스턴스를 생성할 수 없다.

class Student {
	constructor(name) {
    	this.name = name;
    }
}

3. contructor() 내부의 super()

class SmartStudent extends Student {
	constructor(name, score) {
    	this.score = score;
        super(name) // super가 constructor 최상단에 선언된 후 this 바인딩에 접근할 수 있다. TDZ 에러
    }
}

const sally = new SmartStudent('sally', '100')

TDZ는 인스턴스를 초기화하기 위해 부모 클래스의 생성자를 먼저 호출할 것을 제안한다. 부모 클래스 생성자를 호출하고 인스턴스가 준비되면 자식 클래스에서 this 값을 변경할 수 있다.

 

결론

항상 변수의 유효범위에 대해 생각하자. 그리고 변수는 가급적 유효범위 안의 최상단에 선언하고, 세미콜론을 잘 찍자...

728x90