오인된 null 사건
Source: Dev.to
대부분의 개발자는 결국 다음 코드를 보게 된다:
typeof null // "object"
그리고 반응은 보통 즉각적이다:
“잠깐… 뭐지?”
왜냐하면 null은 객체가 아니기 때문이다.
null은 값이 의도적으로 없음을 나타낸다.
그럼 왜 JavaScript는 이를 객체로 인식할까?
1990년대 초반, JavaScript 엔진은 속도와 메모리 효율성을 위해 설계되었다.
값은 아주 작은 32비트 메모리 컨테이너 안에 저장되었다.
어떤 종류의 값이 저장되어 있는지 빠르게 식별하기 위해 엔진은 type tag 라는 숨겨진 이진 마커를 사용했다.
마치 내부 증거 라벨과 같은 것이다. 예를 들면 다음과 같다:
| Type | Conceptual Tag |
|---|---|
| Object | 000 |
| Integer | 001 |
| String | 010 |
| Boolean | 011 |
(단순화된 개념적 표현)
객체는 내부적으로 0 기반의 타입 패턴과 연결되어 있었다. 하지만 null에는 문제가 있었다.
null의 내부 표현은 사실상 모든 비트가 0이었다:
00000000000000000000000000000000
그래서 JavaScript가 값의 타입을 검사할 때…
우연히 객체 태그와 일치하게 된다.
엔진은 사실상 “모든 비트가 0”을 “객체”로 해석한다.
그 결과 null은 잘못 식별된 것이다.
이 실수가 널리 퍼졌기 때문이다.
개발자들이 문제를 인식했을 때쯤, 이미 인터넷 전역의 웹사이트와 애플리케이션이 이 동작에 의존하고 있었다.
이를 수정하면 기존 코드가 대규모로 깨질 것이므로, 버그는 영구적인 것이 되었다.
따라서 다음과 같이 쓰는 대신:
typeof value === "object"
개발자들은 안전하게 다음을 체크하도록 배웠다:
value !== null && typeof value === "object"
추가된 조건은 null이 통과되는 것을 방지한다.
이 버그가 흥미로운 이유는 단순히 잘못된 출력 때문만은 아니다.
JavaScript 초창기의 아주 작은 구현 세부 사항이
수십 년이 지난 현대 애플리케이션에서도 여전히 살아남아 있다는 점이다.
작은 실수 하나.
거대한 레거시 하나.
매우 이상한 범죄 현장 하나.
전체 조사는 TikTok에서 확인할 수 있다:
증거 보기
가장 이상했던 JavaScript 동작은 무엇인가요?