var a;
typeof a // "undefined"
var b = 42 ;
var c;
b=c
b와 c 모두 "undefined"
흔히 "undefined"
(정의가 되지 않아 값이없는 즉 변수는 있는데 이 변수가 뭔지 정의가 되어있지 않는)
와 "undeclared"
(선언 되지 않은 그니깐 변수조차도 선언이 되어있지 않은)
가 같은 동의어 처럼 생각하기 쉬운데 자바스크립트에서 둘은 완전히 다른 개념이다.
"undefind"는 접근 가능한 스코프(이후 나중에 다루게된다)에 변수가 선언되었으나 아무런
값도 할당되지 않은 상태를 가리키는 반면
"undeclared"는 접근 가능한 스코프에 변수 자체가 선언 조차 되지 않은 상태를 의미한다
하지만 브라우저에선 선언되지(undeclared) 않은 변수에 대해서
다음과 같이 에러를 발생시킨다
아니 언디클레어드 인데 왜 낫디파인드라고 하는건지? not declared라고 명확히 명시해줬으면 좋겠지만... 그렇지 않음을 기억하자
또한 이 변수에 대한 typeof 연산자에 결과는 더 헷갈린다.var a;
typeof a // "undefined"
typeof b // "undefined"
"undeclared"인 변수도 "undefined"라고 나온다 이것을 바로 typeof 만의 독특한 안전가드라고한다.
아쉬운 부분이지만 undefined와 undeclared를 구분해 주었으면 충돌할 일도 없었을 탠데,,
그런데 브라우저에서 자바스크립트 코드를 처리할 때 특히 여러 스크립트 파일의 변수들이 전역 네임스페이스를 공유할때 typeof 의 안전 가드는 의외로 쓸모가 있다고한다.
만약
var debug = true
라는 변수가 debug.js라는 파일에 선언되어있고 개발/태스트 단계에서 이 파일을 브라우저가 로딩하기만 하면 된다고 했을 때 다른 나머지 애플리케이션 코드에서 ReferenceError가 나지 않도록 하려면 (선언된적 없는 변수(undeclared))를 체크하려고하면
흔히들
if(debug){retrun "실행코드"}
으로 테스트 하려고하겠지만 만약 debug.js에 있는 변수를 어떠한 사정으로 찾지 못했다면
해당 코드는 바로 ReferenceError 을 토해낼 것이다.
때문에 이럴 경우 typeof 의 안전가드를 활용하여
if(typeof debug!=="undefined"){ return "실행코드"}
으로 코드를 작성하여 에러를 방지하고 코드를 실행 시킬 수있다.
또하나 꽤나 안전하게 체크 할 수 있는 방법이 있는데 전역 객체(브라우저는 window)의 프로퍼티라는 점을 이용하면된다.
if(window.DEBUG){}
if(!window.DEBUG){}
어떤 객체를 통해 접근하게 되면 해당 프로퍼티가 존재하지 않아도 ReferenceError가 나지 않는다.
하지만 이방법은 그렇게 좋은 방법이 아닌데 변수를 window객체로만 호출하지 않는 다중 자바스크립트 환경(브라우저뿐만 아니라 서버(이하 node.js의 express나 nest.js 혹은 http패키지를 사용할경우))
에선 window객체로만 호출하지 않는다.
때문에 적절히 typeof의 안전가드를 사용하여 체크를 하면 되겠다.
여기서 하나더 카카오톡 "풀스택 연구소" 톡방에 계신 '휴학생'님이 추천해주신 싸이트
(TDZ을 모른체 자바스크립트 변수를 사용하지 말라!)를 참조하여 TDZ를 정리해 본다.
class 와 function (둘다 오브젝트)를 var처럼 써본다면?(호이스팅을 하는것처럼!)
// 1번째 case
new Car('red') // ReferenceError (undeclare)
class car {
constructor(color){
this.color =color;
}
}
// 2 번째 case
greet('wrold') // 동작한다
function greet(who){
return `hello, ${who}`
}
왜 이렇게 동작을 할까?
그것을 알려면 TDZ에 대해서 알 필요가 있다.
(Temporal Dead Zone : 일시적 사각 지대)
TDZ는 let, const, class 구문의 유효성을 관리한다 자바스크립트에서 변수가 동작하는 방식은
꽤나 중요하다
일단 가장 만이 쓰이는 const부터 선언해보자
const white ="#FFFFFF"
console.log(white) //잘 동작한다.
이번에는 선언 전에 white
변수에 접근해보도록 하겠다.
white /// throws ReferenceError
const white ="#FFFFFF"
console.log(white) //잘 동작한다.
white가 const으로 선언되기 전까지 white
변수는 TDZ에 있다.
그림으로 표현하자면
이와같다
선언과 정의가 되어지기 전에 변수가 쓰여지면 그곳은 일시전 사각지대가 되어 'ReferenceError'을 토해낸다.
TDZ 시맨틱은 선언 전에 변수에 접근하는 것을 금지한다. TDZ는 징계를 내린다: 변수 선언 전에 어떤 것도 사용하지 않는다.
TDZ의 영향을 받는 구문들을 살펴보자.
class MuscleCar extends Car {
constructor(color,power){
this.power=power // ReferenceError을
super(color)
}
}
/* this 바인딩은 super 보다 앞에 오면 ReferenceError을 토해낸다
이또한 부모를 상속 받았다면 생성자 안에서 슈퍼가 함수가 호출되기 전에는 TDZ이기 때문에 this 을 사용할 수없다.*/
const a =2
function square(a=a){
retrun a*a
}
//함수를 실행하면 ReferenceError을 토해낸다.
기본 변수 a는 선언 전에 a=a 표현식의 오른쪽에서 사용되어 a에서 참조 에러가 발생
기본 변수는 선언 및 초기화 다음에 사용되어야 한다. 보통 이경우 기본 매개변수 명을 init을 칭한다.
위에 설명한 구문들은 TDZ의 영향을 받지 않는다 이것을 현재 스코프에서 호이스팅
(hoisting : 끌어올리기) 된다.
말그대로 아래있는 값을 위로 끌고 올라온다.
value // undefined(undeclare가 아닌 이유는 이유 => 아래 값을 hoisting 했기때문)
var value ;
변수에 경우 선언하기전에 접근하면 undefined가 되지만
함수에 경우 어디에서든 호출해도 동일하게 호출이 된다.
greet('hi') // hi
function greet (say){
return console.log(say)
}
greet('hi')
여기서 import도 호이스팅이 가능하다.
myfunction()
import {myfunction} from './myModule'
여기서 방금 우리가 배운 typeof 안전가드가 나온다
// 선언되지 않은 변수를 타입 체크 할 경우
typeof notDefined // undefined 가나온다
그리고 여기서 안전가드를 무시한 결과도 낼수가 있다
TDZ의 변수를 타입체크하는 방법이다
typeof variable
let variable
typeof 는 TDZ에 있는 변수를 체크할경우 RefernceError을 토해낸다.
또한 TDZ는 선언문이 존재하는 "스코프" 범위 안에서 변수에 영향을 준다
function doSomething(someVal) {
// Function scope
typeof variable; // => undefined
if (someVal) {
// Inner block scope
typeof variable; // throws `ReferenceError`
let variable;
}
}
doSomething(true);
TDZ는 const, let, class 구문의 유효성에 영향을 미치는 중요한 개념이다. TDZ는 선언 전에
변수를 사용하는 것을 허용하지 않는다.
반대로 var 변수는 선언 전에도 사용할 수 있기 때문에 var 사용은 피하는 것이 좋다.
typeof 는 TDZ존에 있는 변수를 체크할땐 ReferenceError을 토해낸다.