Null — один из семи примитивных типов данных в JavaScript (остальные —строки, числа, булевые значения, undefined, BigInt и Symbol).
И только для типа null проверка typeof возвращает объект. Значит ли это, что null — объект? Нет
Null все-таки примитив. История с типом — баг при создании JavaScript.
Так как же он работает?
В первой версии JS значения хранились в 32-битных ячейках. Первые биты были тегами, то есть указывали на тип данных, к которому принадлежит значение.
Таких тегов было 5:
000 — объект
1 — целое число
010 — double (дробное число)
100 — строка
110 — boolean
То есть теги занимали три первых бита в 32-битной ячейке (и один бит в случает целых чисел).
У типа null не было своего отдельного тега. При этом, значение null хранится в памяти в виде нуля (0000, т.е. во всех отведенных под значение битах — нули).
А мы помним, что если у нас в начале значения 000, то программа воспринимает их как тег объекта. Вот и получается такой баг, который разработчики признали, но решили не менять, т.к. это может поломать все уже существующие программы.
Источники: The history of “typeof null” (большинство информации отсюда), A quick and thorough guide to ‘null’