Почему typeof null === ‘object’?
Все JavaScript-программисты давно привыкли к тому, что typeof null === ‘object’; // true , хотя фактически null — примитивное значение. Многие знают, что это баг, и лично Брэндан Айк это признает. Этот баг, вероятно, никогда не будет исправлен из-за необходимости сохранения обратной совместимости существующего кода с новыми версиями языка.
Интересна история того, как же это получилось. Она восходит корнями к первой версии языка, а именно — к тому факту, что значения переменных хранились в 32-битных ячейках в следующем формате:
29-31 бит: само значение;
1-3 бита: метка типа данных;
Было всего пять вариантов метки типа:
000: object;
1: integer;
010: double;
100: string;
110: boolean;
Соответственно, если младший бит был равен единице, то оставшийся 31 бит интерпретировался как integer. Если 0 — то тип определялся в зависимости от значения следующих двух бит.
Также было два специальных зарезервированных значения:
undefined (JSVAL_VOID) — целое –2 30
null (JSVAL_NULL) — указатель на NULL (machine code NULL pointer), то есть, метка объекта и ссылка на то, что его численное представление равно нулю.
Так и вышло, что typeof стал определять null как object — он проверял метку типа, которая сообщала ему, что null — это не что иное, как object.
Значение null для объектов. Как это выглядит?
Про undefined: я думаю для того, чтобы значение объекта было undefined, надо просто в нем ничего не писать.
let object = < //ничего здесь нет >
Про null: ну а про null не понятно. Мы же не можем сделать вот так:
let object = < null >//--> Синтаксическая ошибка
Отслеживать
задан 10 апр 2021 в 20:59
1,869 8 8 серебряных знаков 21 21 бронзовый знак
let object = null;
10 апр 2021 в 21:08
Вы путаете объект и переменную. «Если переменная, представляющая объект, будет иметь значение null». Переменная иметь значение.
– user347472
10 апр 2021 в 21:11
@Алексей Шиманский Так это ж просто обычная переменная, которой вы присвоили значение null . Объект вроде как должен создаваться либо с помощью фигурных скобок, либо с помощью new Object()
10 апр 2021 в 21:38
«Если переменная, представляющая объект, будет иметь значение null или undefined цикл не выполнится ни разу.» => Если есть какая-нибудь переменная, которая предназначена для хранения объекта, но в данный момент она хранит не объект, а значение null или undefined , то цикл не выполнится ни разу.
Исследование бездны null и undefined в JavaScript

Говоря о примитивных типах данных в JavaScript, большинство имеет в виду самые основные из них: String, Number, и Boolean. Эти примитивы достаточно предсказуемы, и работают так, как от них и ожидается. Однако, речь в данной статье пойдет об менее обыденных примитивных типах, Null и Undefined, о том, в чём они схожи, различны, и, вообще говоря, необычны.
Понимание null и undefined
В JavaScript null — это литерал и ключевое слово языка, которое представляет собой отсутствие какого-либо объекта. Другими словами, null указывает «в никуда». В свою очередь, хоть и похожий по смыслу undefined , олицетворяет отсутствие значения как такового. Оба абсолютно неизменны, не имеют свойств и методов и не способны их иметь. Фактически, попытка обратиться к какому-нибудь свойству, или присвоить его, приведёт к ошибке TypeError . Оба этих примитива, как намекают их имена, совершенно лишены значений.
Это самое отсутствие значения приводит к тому, что они считаются ложными, в том смысле, что они приводятся к false если используются в качестве условия, например, в конструкции if . А если сравнить null и undefined с другими ложными значениями при помощи оператора нестрогого сравнения ( == ), то окажется, что они не равны ничему, кроме самих себя:
null == 0; // false undefined == ""; // false null == false; // false undefined == false; // false null == undefined; // true
Несмотря на эти сходства, null и undefined не эквивалентны. Каждый из них является представителем своего типа: undefined — представляет тип Undefined, а null , соответственно — тип Null. Это легко доказать, сравнив их при помощи оператора строгого сравнения ( === ), который принимает в расчёт не только значения, но и типы данных:
undefined === null; // false
Это важное различие, и оно не случайно, ведь эти примитивы служат для разных целей. Чтобы их различать, вы можете считать undefined неожиданным отсутствием значения, а null — умышленным отсутствием значения.
Получение undefined
Есть множество способов получить значение undefined в коде. Обычно это происходит при попытке получить значение там, где значения нет. В этом случае JavaScript, будучи динамическим, слабо типизированным языком, не покажет ошибку, а выдаст значение по умолчанию, undefined .
Любая объявленная переменная, которой при создании не присвоено никакого значения, имеет значение undefined :
var foo; // по умолчанию undefined
Значение undefined также получается при попытке обратиться к несуществующему свойству объекту или элементу массива:
var array = [1, 2, 3]; var foo = array.foo; // свойство foo не существует, возвращается undefined var item = array[5]; // в массиве нет элемента 5, возвращается undefined
Если в функции нет оператора return , она возвращает undefined :
var value = (function( )<>)(); // возвращает undefined
Если функции не был передан какой-либо аргумент, он становится undefined :
(function(undefined)< // параметр равен undefined >)();
Помимо всего вышеперечисленного, для получения undefined может использоваться оператор void . Некоторые библиотеки, вроде Underscore пользуются этим для надежной проверки типов, потому как void нельзя переопределить, и он всегда возвращает undefined :
function isUndefined(obj)< return obj === void 0; >
Наконец, undefined — это предопределённая глобальная переменная (а не ключевое слово, как null ), которая равна undefined :
'undefined' in window; // true
Начиная с пятой версии ECMAScript эта переменная доступна только для чтения, а, вот, в предыдущих версиях её было возможно переопределить.
Применение null
В первую очередь null отличается своим применением, и в отличие от undefined , null больше используется для присваивания значения. Как раз из-за этого оператор typeof для null возвращает «object». Изначально это объяснялось тем, что null использовался (и используется) как пустая ссылка там, где ожидается объект, что-то вроде заглушки. Такое поведение typeof было позже признано багом, и, хотя было предложено это поведение исправить, пока что, в целях обратной совместимости, всё остается как есть.
Вот, почему окружение JavaScript не выставляет никаких значений в null , и это делается только программно. В документации на MDN написано следующее:
В различных API null часто возвращается в тех местах, где ожидается объект, но такой объект подобрать нельзя.
Это правдиво для DOM, который не зависит от языка и никак не описывается в документации ECMAScript. Из-за того, что используется внешний API, попытка получить отсутствующий элемент возвращает null , а не undefined .
Вообще, если нужно присвоить «не-значение» переменной или свойству, передать его в функцию, или вернуть из функции, то null — это почти всегда лучший вариант. Упрощённо: JavaScript использует undefined , а программисты должны использовать null .
Другой способ применения null — явное «зануливание» переменной ( object = null ), когда ссылка на объект больше не требуется. Кстати, это считается хорошей практикой. Присваивая null , вы фактически удаляете ссылку на объект, и если на него нет других ссылок, он отправляется к сборщику мусора, таким образом возвращая доступную память.
Копнём глубже
Причина того, что null и undefined эдакие чёрные дыры, кроется не только в их поведении, но ещё и в том, как они обрабатываются внутри окружения JavaScript. Они не обладают теми характеристиками, которые обычно присущи другим примитивам и встроенным объектам.
Начиная с ES5 метод Object.prototype.toString , ставший стандартом де-факто для проверки типов, стал полезен в этом отношении и для null с undefined :
Object.prototype.toString.call(null); // [object Null] Object.prototype.toString.call(undefined); // [object Undefined]
Однако, на самом деле у null и undefined этот метод не возвращает внутреннее свойство [[Class]] . По документации он работает следующим образом:
- Если значение this равно undefined , вернуть «[object Undefined]» .
- Если значение this равно null , вернуть «[object Null]» .
- Пусть O равно результату вызова ToObject с this , переданным как аргумент.
- Пусть class равно внутреннему свойству [[Class]] объекта O.
- Вернуть значение String, которое является результатом сложения трёх строк «[object » , class, и «]» .
Этот метод просто возвращает заготовленную строку, если обнаруживает null или undefined , просто чтобы унифицировать функциональность с другими объектами. Такое поведение встречается сплошь и рядом во всей документации, большая часть методов содержат простую проверку, и если встретился null или undefined , возвращают значение сразу. Фактически, нигде не написано, что у них содержатся какие-либо внутренние свойства, обычно имеющиеся у каждого нативного объекта. Это как если бы они вообще не были объектами. Интересно, эти примитивы в окружении JavaScript как-то явно и особо обрабатываются? Может быть, кто-то более знакомый с имплементацией мог бы подсказать.
Заключение
Неважно, насколько необычными кажутся примитивы null и undefined , понимание разницы между ними и их различиями в использовании согласно JavaScript очень важно для понимания языка в целом. Это понимание, конечно же, само по себе не заставит работать ваше приложение или, например, не сломает его, но, строго говоря, оно положительно скажется в долгосрочной перспективе, облегчив вам разработку и отладку будущих проектов.
Комментарий переводчика
При написании этой статьи автор забыл упомянуть одну важную деталь: у примитивов, как таковых, не может быть свойств вообще, они есть только у объектов. А при попытке получить свойство у примитива, он будет неявно преобразован в объект. В этом легко убедиться:
var s = 'test', o = Object(s); o.foo = 42; s.foo = 42; o.foo; // 42 s.foo; // undefined
Дело в том, что null и undefined просто нельзя преобразовать в объект, на чем и строится объяснение ключевых особенностей этих примитивов автором этой статьи.
Также, фраза про то, что null в окружении JavaScript без явного присваивания не используется, неверна. В конце цепочки прототипов находится null , и это как раз тот случай, когда ожидается объект, но его нет:
Object.getPrototypeOf(Object.prototype); // null
![]()
Оригинальная статья: Exploring the Abyss of Null and Undefined in JavaScript Статью вычитывали: SilentImp, cosmiksoul, FMRobot, subzey
© 2013 Frontender Magazine
Кроме материалов, опубликованных под лицензией Creative Commons
Евгений Степанищев

Пишу, по большей части, про историю, свою жизнь и немного про программирование. Живу в Казани.
Почему у null в JS тип «object»?
На «Хабре» вышла статья, проливающая свет на загадку — почему же у null в Джаваскрипте тип «объект». Причём, если попытаться этому «объекту» добавить какое-то свойство, то браузер воспротивится: скажет, что null объектом не является.
![]() |
Вообще, я этому особого значения не придавал. Ну да, примитивное значение, имеет тип объект, хотя по факту им не является, смысла я в этом не вижу, это мешает, но поменять это нельзя.
Оказывается, это баг. Точнее даже не баг, а просто «так получилось». В ранних интерпретаторах Джаваскрипта тип хранился в первых трёх битах значения. Для типа «а это у нас null» значения не хватило, ему дали тип «объект», а под значение выделили нулевой указатель. Ну typeof, особо не заморачиваясь, выдавала object.
К сожалению, программисты поленились сделать дополнительную проверку. Можно было при наличии нулевого указателя попросить typeof выводить «null» и дело в шляпе. Сейчас, как оказалось, куча кода завязано на это поведение и ломать уже ничего никто не будет.
9 комментариев
Если уж хочется что-то поменять, то логичнее будет расширить поведение до полноценного Object? Хоть какая-то польза может выйти.
История в тему: недавно на собеседовании вьюноши учудили и начали спрашивать меня про типы данных. Тогда про null для них и случилось открытие ) Детишки про фишку тупо не знали. Ясно, что на работу уже не позвали. А снаружи это вполне солидный ресурс.
Евгений Степанищев (bolknote.ru) 2014
Комментарий для shaltai-boltai:
Честно сказать, если его расширить, то мне польза неочевидна как-то 🙂 Давать ему методы через прототип? 🙂 Разве что только для целостности языка какая-то польза будет.
А вот проблемы некоторые это рождает. Например, известнейшая проверка «а объект ли это» снабжается костылём «и не null».
Ну да, больше для целостности. Null-объект можно делать типизированным, можно какую-то историю для undo хранить. Всё лучше, чем ничего.
Ну вообще-то, NULL теоретически подпадает под возможное значение объекта.
Во многих языках с проверкой типа любой объект может быть NULL.
Я думал из этих побуждений и здесь так сделано, а не баг.
Но, конечно на практике в JS это не удобно.
