Menu

자바스크립트 null vs undefined 차이와 체크 방법 정리

자바스크립트에서 null과 undefined가 실제로 어떻게 다른지, 두 값을 어떻게 체크하는지, 그리고 내 코드에선 어느 쪽을 써야 할지까지 한 번에 정리했습니다.

"없음"을 표현하는 두 가지 방법

대부분의 언어에서는 "값이 없음"을 나타내는 값이 하나뿐이지만, 자바스크립트에는 nullundefined 두 가지가 있다. 둘은 비슷해 보여서 초보자를 헷갈리게 만들고, 또 미묘하게 달라서 경력 개발자도 발목을 잡히곤 한다. 10분만 투자해서 둘의 차이를 확실히 짚고 넘어갈 만한 가치가 있다.

간단히 정리하면 이렇다:

  • undefined자바스크립트가 값이 비어 있을 때 알아서 넣어주는 값이다.
  • null개발자가 "여긴 의도적으로 비워 뒀어"라고 직접 적어 넣는 값이다.
index.js
Output
Click Run to see the output here.

위 예시에서 패턴이 보이나요? undefined가 등장한 건 전부 자바스크립트가 값을 찾지 못했을 때이고, null이 등장한 건 누군가 직접 타이핑해서 넣었을 때입니다.

undefined가 나타나는 경우

undefined는 몇 가지 정해진 상황에서만 등장하는데, 공통점은 모두 "값이 없다"는 변주입니다:

index.js
Output
Click Run to see the output here.

어느 경우든 자바스크립트가 값을 찾으려 했는데 아무것도 없었다는 뜻입니다. undefined는 엔진이 "찾아봤지만 값이 없더라"라고 알려주는 방식이죠.

물론 undefined를 직접 할당할 수도 있습니다 (let x = undefined;). 하지만 그러지 마세요. undefined는 "자바스크립트가 아무것도 찾지 못했다"는 신호로 남겨두는 게 좋습니다. 내가 직접 "값이 없음"을 표현하고 싶을 때는 null을 쓰세요.

null은 어디서 올까

null은 누군가 직접 써넣어야만 나타납니다. 바로 그게 핵심이에요 — null은 의도적으로 표시해 둔 값이거든요.

index.js
Output
Click Run to see the output here.

DOM API는 null을 자주 돌려줍니다. 예를 들어 document.getElementById("missing")undefined가 아니라 null을 반환하죠. 브라우저가 "찾아봤는데 해당 요소가 없다"라고 명시적으로 알려주는 셈입니다. JSON.parse("null")도 마찬가지로 null을 돌려줍니다. JSON 스펙 자체에 undefined가 없기 때문이죠.

정리하자면 이렇게 기억하면 편합니다. undefined는 기본적으로 비어 있는 상태, null은 개발자가 의도적으로 비워둔 상태입니다.

typeof null이 "object"인 이유

자바스크립트의 대표적인 함정 중 하나입니다.

index.js
Output
Click Run to see the output here.

typeof null"object"를 반환하는 건 1995년부터 있던 버그인데, 이걸 고치면 기존 웹사이트들이 다 깨져버리니까 그냥 영구적으로 남겨둔 거예요. null객체가 아닙니다. undefined, 숫자, 문자열, 불리언처럼 엄연한 원시값(primitive)이죠. 그저 typeof 결과가 거짓말을 할 뿐입니다.

그래서 실전에서 중요한 포인트가 하나 있어요. null을 판별할 때 typeof는 아무 쓸모가 없습니다. 직접 비교해야 해요:

index.js
Output
Click Run to see the output here.

혹은 더 흔하게는 둘 중 어느 쪽이든 한 번에 확인하는 방법이 있는데, 바로 다음 섹션에서 다룬다.

둘 다 한 번에 체크하기: == null 관용구

사실 대부분의 경우 값이 어느 쪽 으로 비어 있는지는 중요하지 않다. 그냥 값을 쓰기 전에 "비어 있나?"만 확인하고 싶을 뿐이다. 이럴 때 자바스크립트에서 쓰는 관용적인 null 체크 방법은 null과의 느슨한 동등 비교(==)다:

index.js
Output
Click Run to see the output here.

value == null은 정확히 nullundefined일 때만 true를 반환하고, 0, "", false 같은 값에는 false를 반환합니다. 대부분의 경우 우리가 원하는 바로 그 동작이죠. === 대신 ==를 써도 되는 거의 유일한 경우이고, 린터들도 이 패턴은 예외로 허용해 줍니다.

좀 더 명시적으로 쓰고 싶다면 value === null || value === undefined라고 풀어 써도 의미는 동일하고, 오히려 의도가 더 분명하게 드러납니다.

Nullish 연산자: ???.

nullundefined를 다루기 편하게 하려고 도입된 연산자가 두 개 있습니다. 둘 다 nullundefined는 똑같이 취급하고, 나머지 값은 건드리지 않습니다.

**Nullish 병합 연산자(??)**는 왼쪽 값이 null이거나 undefined일 때만 기본값으로 대체합니다:

index.js
Output
Click Run to see the output here.

|| 연산자는 0을 falsy로 취급해서 3으로 바꿔버립니다. 반면 ??는 좀 더 엄격해서 오직 nullish한 두 값(null, undefined)에 대해서만 동작합니다.

옵셔널 체이닝(?.) 은 체인을 따라가다 null이나 undefined를 만나면 평가를 멈추고 undefined를 반환합니다:

index.js
Output
Click Run to see the output here.

두 연산자 모두 "이 값이 nullish인가?"를 확인하는 질문이 워낙 자주 등장하기 때문에 존재합니다. 뒤에서 더 자세히 다룰 예정이니 가볍게 기억해두세요.

기본 매개변수는 undefined일 때만 동작한다

자주 놓치는 포인트 하나. 함수의 기본 매개변수 값은 null이 아니라 undefined가 전달됐을 때만 적용됩니다.

index.js
Output
Click Run to see the output here.

null을 넘기면 "값 없음을 내가 일부러 선택했다"는 뜻으로 받아들여 그대로 사용합니다. null일 때도 기본값으로 대체하고 싶다면 함수 안에서 ??를 쓰면 됩니다:

index.js
Output
Click Run to see the output here.

이 차이 때문에 많은 사람들이 헷갈려합니다. 기본값은 인자가 빠졌을 때 동작하고, ??nullish 값일 때 동작합니다.

JSON에는 undefined가 없다

JSON에는 null은 있지만 undefined는 없습니다. 그래서 직렬화할 때 조용히 엉뚱한 결과가 나오는 경우가 있죠:

index.js
Output
Click Run to see the output here.

age 필드가 아예 사라져 버렸죠. JSON.stringify는 값이 undefined인 프로퍼티를 그냥 날려 버립니다. 반면 null은 JSON 표준에 포함되어 있어서 그대로 살아남습니다. 객체를 JSON으로 변환했다가 다시 되돌리는 과정에서 undefined 프로퍼티가 소리 소문 없이 사라지는 건 정말 흔한 함정이에요.

배열 안에서는 undefinednull로 바뀝니다:

index.js
Output
Click Run to see the output here.

API 응답 페이로드를 설계할 때 "값 없음"을 표현하고 싶다면 undefined보다 null을 쓰는 게 좋습니다. 직렬화 과정을 거쳐도 살아남으니까요.

null과 undefined, 언제 어떤 걸 써야 할까

직접 짜는 코드라면 이 정도 규칙을 따르면 무난합니다.

  • undefined는 "제공되지 않음"을 의미하게 두세요 — 전달되지 않은 인자, 초기화되지 않은 변수, 존재하지 않는 프로퍼티 같은 경우죠. undefined를 직접 대입하지는 마세요.
  • null은 "의도적으로 비워 뒀다"는 걸 명시하고 싶을 때 씁니다 — 로그아웃 상태의 사용자, 아직 선택되지 않은 옵션, 지워진 폼 필드처럼요.
  • API 경계에서는 둘 다 받아주되(== null이나 ??를 활용하세요), 내보내는 쪽은 하나로 통일하는 게 좋습니다.

어떤 스타일 가이드(TypeScript 공식 가이드 포함)는 아예 null을 쓰지 않고 undefined만 사용하기도 합니다. 충분히 일리 있는 선택이에요 — 한 가지만 있으면 두 개보다 단순하니까요. 프로젝트마다 규칙을 정하고 일관되게 적용하는 게 핵심입니다.

다음 주제: 타입 변환(Type Coercion)

nullundefined는 자바스크립트가 숫자, 문자열, 불리언으로 변환할 때 각자 다르게 동작합니다 — Number(null)0이지만 Number(undefined)NaN이죠. 이런 비대칭성이 실제로 버그를 만듭니다. 다음 글에서는 타입 변환을 다룰 텐데, 전체 규칙을 한번 파악하고 나면 자바스크립트의 기묘해 보이던 동작들이 더 이상 미스터리처럼 느껴지지 않을 겁니다.

자주 묻는 질문

자바스크립트에서 null과 undefined는 뭐가 다른가요?

undefined는 "아직 값이 할당되지 않았다"는 뜻입니다. 선언만 하고 값을 안 넣은 변수, 전달하지 않은 인자, 존재하지 않는 객체 프로퍼티에 접근했을 때 자바스크립트가 알아서 돌려주는 값이죠. 반면 null은 개발자가 "여기엔 값이 없다"라고 직접 명시해서 넣는 값입니다. 자바스크립트 엔진이 스스로 null을 만들어내는 경우는 없고, 항상 사람이 직접 타이핑해서 넣는 값이에요.

null과 undefined를 한 번에 체크하려면 어떻게 하나요?

value == null을 쓰면 됩니다. 느슨한 비교(==)는 nullundefined를 서로 같다고 보고, 다른 값과는 같다고 보지 않습니다. 그래서 x == null은 정확히 이 두 값일 때만 true가 돼요. 평소에는 ===을 쓰라고 하지만, 이 패턴만큼은 ==가 관용적이고 안전한 거의 유일한 케이스입니다.

typeof null이 왜 'object'로 나오나요?

자바스크립트 초창기부터 있던 버그인데, 지금 고치면 기존 웹이 다 깨지기 때문에 어쩔 수 없이 남아 있습니다. null은 분명히 원시값(primitive)인데도 typeof null'object'를 반환해요. 그래서 null만 정확히 걸러내고 싶다면 value === null처럼 직접 비교하는 게 정답입니다.

제 코드에선 null과 undefined 중 어느 걸 써야 하나요?

일반적인 컨벤션은 이렇습니다. undefined는 "아무것도 주어지지 않았다"는 의미로 두고, null은 "의도적으로 비어 있다"고 명시하고 싶을 때만 사용하는 거예요. 사실 TypeScript 공식 스타일 가이드처럼 아예 null을 안 쓰고 undefined로만 통일하는 팀도 많습니다. 어느 쪽이든 프로젝트 안에서는 하나의 규칙으로 통일해서 쓰는 게 제일 중요합니다.

Coddy로 코딩 배우기

시작하기