JavaScript에서 undefined 확인하는 방법 — typeof vs in 연산자

1. 문제 정의

JavaScript에서 변수가 undefined인지 확인할 때 개발자들은 여러 가지 방식을 사용합니다. 대표적으로 다음과 같은 코드가 흔히 등장합니다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
// 방법 A: window의 속성으로 확인
if (window.myVariable) {
  // ...
}

// 방법 B: typeof 연산자 사용
if (typeof(myVariable) != "undefined") {
  // ...
}

// 방법 C: 직접 비교 (에러 발생 위험)
if (myVariable) {
  // ...
}

문제는 각 방법이 ‘변수가 무엇을 의미하는지’에 따라 동작이 완전히 다르다는 점입니다. 특히 방법 C는 변수가 선언되지 않았을 때 다음과 같은 에러를 발생시킵니다.

1
ReferenceError: myVariable is not defined

출처: StackOverflow 3390396 - How can I check for “undefined” in JavaScript?

2. 원인 탐구

왜 같은 ‘undefined 확인’ 코드인데 동작이 제각각일까요? 그 이유는 undefined라는 개념이 실제로 두 가지 서로 다른 상황을 포함하기 때문입니다.

상황설명typeof 결과
선언되지 않은 변수var/let/const로 선언된 적이 없음"undefined"
선언됐지만 값이 없는 변수선언만 하고 초기화하지 않음"undefined"

선언되지 않은 변수에 직접 접근하면 JavaScript 엔진이 ReferenceError를 던집니다.

1
2
3
4
// abc는 한 번도 선언된 적이 없다.
if (abc) {
  // ReferenceError: abc is not defined
}

따라서 if (myVariable) 같은 직접 접근 방식은 변수가 미선언 상태일 때 프로그램을 즉시 중단시킵니다. 이 에러를 피하려고 Try/Catch를 감싸야 하는지가 질문의 핵심입니다.

또 하나의 함정은 if (window.myVar) 방식입니다. window 속성 접근은 비교가 되지만, falsy 값을 모두 걸러내기 때문입니다.

1
2
3
4
5
6
7
// 아래 값들은 모두 if 조건에서 거짓으로 처리된다.
false
0
""
NaN
null
undefined

즉, 변수의 값이 실제로 0이나 빈 문자열이라면 if (window.myVar)로는 undefined와 구분할 수 없습니다.

3. 근본 원인 분석

근본 원인은 확인하고 싶은 것이 ‘존재 여부’인지 ‘값의 종류’인지에 따라 적절한 연산자가 다르다는 데 있습니다.

1) 변수가 선언되었는지(존재 여부)를 알고 싶다면 → in 연산자

in 연산자는 변수가 선언됐는지 여부를 값과 무관하게 확인합니다.

1
2
3
4
5
6
7
// 전역 스코프
var theFu; // theFu는 선언되었지만 값은 undefined

typeof theFu; // "undefined"  ← 값 기준이므로 undefined로 나온다

"theFu" in window;  // true   ← 존재 여부 기준
"theFoo" in window; // false  ← 선언된 적 없음

in 연산자는 ‘선언됐지만 초기화되지 않은 변수’도 true로 판별합니다. 값이 아닌 존재 자체를 보기 때문입니다.

2) 변수의 값이 undefined인지 알고 싶다면 → typeof 연산자

typeof는 항상 문자열을 반환하므로, 변수가 선언되지 않아도 ReferenceError 없이 안전하게 확인할 수 있습니다.

1
2
3
if (typeof myVar !== 'undefined') {
  // myVar가 undefined가 아님
}

3) 왜 undefined와 직접 비교하면 안 되는가?

과거에는 window.undefined를 덮어쓸 수 있었기 때문에 직접 비교가 오염될 수 있었습니다.

1
2
window.undefined = "foo";
"foo" == undefined // true  ← 오염된 비교

다만 @CMS가 지적했듯이, 이는 ECMAScript 5판에서 패치되어 undefined는 더 이상 쓸 수 없게(non-writable) 되었습니다. 그럼에도 typeof 비교는 명시적이고 안전한 관례로 남아 있습니다.

4) 직접 접근이 에러를 일으키는 두 번째 경우

if (myVariable)은 미선언 변수 접근뿐 아니라, getter 함수가 내부에서 예외를 던지는 속성을 접근할 때도 ReferenceError(또는 기타 예외)를 발생시킬 수 있습니다.

4. 코드 해결책

상황에 맞는 안전한 undefined 판별 코드를 정리합니다.

해결책 1: 값이 undefined인지 확인 (가장 일반적)

1
2
3
4
5
6
7
8
9
// 선언 여부와 무관하게 값이 undefined인지 안전하게 확인
if (typeof myVar === 'undefined') {
  console.log('myVar는 undefined입니다.');
}

// !== 'undefined'로 부정 확인
if (typeof myVar !== 'undefined') {
  console.log('myVar에 값이 있습니다.');
}

해결책 2: 변수/속성이 선언(존재)되었는지 확인

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
// 전역 변수 존재 여부
if ("myVar" in window) {
  console.log('myVar가 전역에 선언되었습니다.');
}

// 객체 속성 존재 여부 (hasOwnProperty와 병행 가능)
const obj = {};
if ("key" in obj) {
  console.log('obj에 key 속성이 존재합니다.');
}

해결책 3: NaN 등 다른 falsy 값과 구분

값 자체가 false, 0, "", NaN, null이어도 그 값은 유효한 데이터일 수 있습니다. 값을 보존하면서 판별하려면 진리값 검사 대신 typeof를 쓰는 것이 안전합니다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
const count = 0;

// ❌ 값이 0인데도 undefined처럼 취급된다
if (count) {
  // 실행되지 않음
}

// ✅ 0은 undefined가 아니므로 정상적으로 구분된다
if (typeof count !== 'undefined') {
  console.log('count는 정의되어 있고 값은', count); // count는 0
}

방법별 동작 비교 표

확인 코드미선언 변수값=undefined값=0 / "" / false에러 발생
if (myVar)ReferenceErrorfalsefalse⚠️ 가능
if (window.myVar)falsefalsefalse안전
if (typeof myVar !== 'undefined')falsefalsetrue안전
"myVar" in windowfalsetruetrue안전

typeof myVar !== 'undefined'"myVar" in window 모두 미선언 변수에 대해 false를 반환하지만, in 연산자는 값이 undefined인 변수에 대해서도 true 를 반환한다는 차이가 있습니다.

5. 향후 예방 조치

undefined 확인과 관련된 함정을 피하기 위한 실천 지침입니다.

  1. 미선언 변수 접근을 피하라if (myVar)처럼 변수를 직접 조건에 넣지 말고, 반드시 typeofin으로 감싸서 접근하세요. 직접 접근은 ReferenceError: x is not defined를 일으킵니다.
  2. ‘존재 여부’와 ‘값의 종류’를 구분하라 — 선언됐는지가 궁금하면 in 연산자, 값이 undefined인지가 궁금하면 typeof 연산자를 쓰세요. 둘을 혼용하면 의도와 다른 결과가 나옵니다.
  3. falsy 값 함정을 기억하라if (value)0, "", false, NaN, null, undefined를 모두 거짓으로 만듭니다. 값 자체를 유효 데이터로 다뤄야 한다면 진리값 검사 대신 typeof를 사용하세요.
  4. ES5 이후의 안전성에 의존하라undefined는 SC5에서 non-writable로 고정되었지만, 명시적인 typeof 비교가 코드 의도를 더 잘 드러냅니다.
  5. 모듈/스코프 단위로 변수를 초기화하라 — 변수를 사용하기 전에 명시적으로 초기화하면 미선언 상태 자체가 발생할 여지를 줄일 수 있습니다.

출처