자바스크립트로 개발을 하다 보면 ‘이 값이 정말 존재할까?’라는 걱정이 자주 생기곤 해요. API에서 데이터를 받아오거나, 객체 안을 깊숙이 탐색할 때 갑자기 만나는 undefined는 예상치 못한 오류를 만들기 일쑤죠. 오늘은 이런 상황에서 당황하지 않고, undefined를 안전하게 확인하고 처리하는 여러 가지 방법을 하나씩 정리해볼게요. 상황에 맞는 올바른 방법을 선택하는 것이 안정적인 코드를 만드는 첫걸음이니까요.
목차
undefined가 등장하는 다양한 순간
undefined는 말 그대로 ‘정의되지 않은 상태’를 의미해요. 값이 할당되지 않은 변수, 존재하지 않는 객체의 속성, 전달되지 않은 함수의 인자 등 다양한 형태로 우리를 마주칩니다. 이렇게 다양한 경로로 나타날 수 있기 때문에, 단순히 ‘값이 없네’라고 생각하는 것보다 ‘왜 없을까?’를 고민하는 것이 중요해요.
| 상황 | 예시 |
|---|---|
| 변수 선언만 하고 값 할당 안 함 | let myVar; console.log(myVar); // undefined |
| 존재하지 않는 객체 속성 접근 | const obj = {}; console.log(obj.name); // undefined |
| 함수에 인자 전달 안 함 | function greet(name) { console.log(name); } greet(); // undefined |
| return문 없는 함수 호출 | function noReturn() {} console.log(noReturn()); // undefined |
undefined를 확인하는 실용적인 방법들
가장 안전한 검사 방법
undefined를 확인할 때 어떤 방법이 가장 믿음직스러울까요? 바로 typeof 연산자를 사용하는 방법이에요. 이 방법의 큰 장점은 변수가 아예 선언되지 않았더라도 에러 없이 안전하게 확인할 수 있다는 거죠. 외부 라이브러리나 환경을 신경 써야 하는 경우에도 확실하게 동작해요.
if (typeof value === 'undefined') { // value가 undefined인 경우 처리 }
엄격한 비교와 동시 처리
변수가 이미 선언되었다는 게 확실하다면, === undefined로 엄격하게 비교하는 것도 좋은 방법이에요. 이 방법은 함수의 매개변수나 객체의 속성처럼 확실히 존재하는 공간을 확인할 때 유용해요. 한편, 개발을 하다 보면 null과 undefined를 구분하지 않고 ‘값이 없음’으로 한꺼번에 처리하고 싶을 때가 있어요. 그럴 때는 == null 비교를 사용하면 돼요. 엄격한 동등 연산자를 권장하는 분위기이지만, 오직 null과 undefined를 함께 걸러내기 위한 목적으로는 종종 사용되기도 해요.
편리한 최신 문법 활용하기
ES2020 이후로 우리의 코딩 생활을 편하게 만든 문법들이 있어요. 그중 첫 번째는 옵셔널 체이닝이에요. 객체의 속성을 안전하게 접근할 때 중간에 undefined가 끼어 있어도 코드가 멈추지 않고 그냥 undefined를 반환해주죠. API 응답처럼 계층 구조가 복잡한 데이터를 다룰 때 정말 유용해요.
const userName = apiResponse?.data?.user?.name;
두 번째는 널 병합 연산자예요. 값이 null이나 undefined일 때만 지정한 기본값으로 대체해줘요. 예전에 많이 쓰이던 OR 연산자(||)는 0이나 빈 문자열 같은 falsy 값도 덮어쓰는 문제가 있었는데, 널 병합 연산자는 정말 ‘값이 없을 때’만 작동해서 더 안전하게 사용할 수 있어요.
const displayName = userInput ?? '익명의 사용자';
실제 개발에서 자주 마주치는 상황과 해결책
API 데이터를 안전하게 받아오기
외부 API와 통신할 때는 응답 구조가 예상과 다를 수 있어 항상 방어적으로 코드를 작성해야 해요. 옵셔널 체이닝으로 깊은 속성에 접근하고, 중요한 값이 정말 undefined인지 typeof로 최종 확인하는 패턴이 효과적이에요.
function parseUserResponse(response) { const userId = response?.body?.user?.id; if (typeof userId === 'undefined') { return { ok: false, error: '사용자 ID를 찾을 수 없음' }; } // userId를 안전하게 사용 }
함수와 객체를 다룰 때 주의할 점
함수를 만들 때는 매개변수에 기본값을 설정해두면 undefined가 들어오는 상황을 미리 막을 수 있어요. 또한, 객체의 특정 속성이 존재하는지 여부를 알고 싶을 때는 in 연산자를 사용할 수 있어요. 이 연산자는 속성 자체가 객체에 정의되어 있는지 확인해주기 때문에, 속성 값이 의도적으로 undefined로 설정된 경우와 구분할 때 도움이 돼요.
// 함수 매개변수 기본값 설정 function welcome(message = '안녕하세요') { console.log(message); } // 객체 속성 존재 여부 확인 if ('theme' in settings) { // settings.theme 속성이 존재함 (값이 undefined일 수도 있음) }
undefined와 타입스크립트
타입스크립트를 사용한다면 null과 undefined를 더 엄격하고 명시적으로 다룰 수 있어요. 가장 큰 차이는 undefined는 ‘아직 값이 할당되지 않은 상태’를, null은 ‘의도적으로 값이 없음을 나타낸 상태’를 의미한다는 점이에요. 타입스크립트에서는 이를 union 타입으로 표현하여 어떤 값이 문자열이거나 null이거나 undefined일 수 있다고 정확히 알려줄 수 있어요.
let title: string | null | undefined;
tsconfig.json에서 strictNullChecks 옵션을 켜두면, null이나 undefined가 허용되지 않는 타입에 실수로 할당하는 것을 미리 차단해줘서 런타임 오류를 예방하는 데 큰 도움이 됩니다. 타입스크립트의 타입 가드 기능을 활용하면 조건문 안에서 변수의 타입을 좁혀나가며 안전하게 사용할 수도 있어요.
정리하며
undefined를 다루는 방법은 하나가 아니에요. 상황과 목적에 따라 가장 적합한 도구를 선택하는 것이 현명한 개발자의 자세죠. 가장 널리 쓰이는 조합을 정리해보자면, 변수 존재 여부를 모르는 광범위한 검사에는 typeof를, 안전한 객체 탐색에는 옵셔널 체이닝을, 값이 없을 때의 기본값 할당에는 널 병합 연산자를 우선적으로 생각해보면 좋아요. 타입스크립트를 함께 사용한다면 엄격한 타입 체크를 통해 이러한 실수를 컴파일 단계에서 잡아낼 수 있다는 점도 큰 장점이에요. 이렇게 다양한 방법을 이해하고 프로젝트에 맞게 일관되게 적용한다면, 갑자기 찾아오는 undefined 때문에 당황하는 일은 점점 줄어들 거예요.
