Перевод статьи Everything about null in JavaScript.
Как вы уже, наверное, знаете в языке JavaScript реализовано две большие группы типов данных: примитивы (строки, логические значения, числа, символы) и объекты.
Объекты — это сложные структуры данных. Самым простым объектом в JavaScript является объект представляющий собой набор ключей и соответствующих им значений:
let myObject = { name: 'Eric Cartman' };
Но бывают ситуации, когда объект по разным причинам (отсутствие или некорректные значения аргументов функции и т.д.) не может быть создан. Для таких случаев JavaScript предоставляет специальное значение null
, которое указывает на его отсутствие.
let myObject = null;
В этой статье вы узнаете все о null
в JavaScript: о его использовании, как можно определить его присутствие, а также о разнице между null
и undefined
, и почему использование null
создает трудности в сопровождении кода.
Содержание
1. Концепция null
Спецификация JavaScript говорит следующее о null
:
null
— примитивное значение, которое представляет намеренное отсутствие какого-либо значения типа объект.
Таким образом, если вы замечаете, что значение null
было присвоено переменной или возвращается функцией, то этим значением, в общем случае, должен быть объект, но по какой-то причине он не был создан.
Например, функция greetObject()
создает объекты, но также она может возвращать null
, если объект не может быть создан:
function greetObject(who) { if (!who) { return null; } return { message: `Hello, ${who}!` }; } greetObject('Eric'); // => { message: 'Hello, Eric!' } greetObject(); // => null
И так, при вызове функции со строковым аргументом greetObject('Eric')
, как и ожидалось, функция возвращает объект { message: 'Hello, Eric!' }
.
Однако при вызове функции без аргументов greetObject()
функция возвращается null
. Возврат в качестве значения null
кажется разумным, так как параметр who
по сути не имеет значения, и поэтому объект с информацией о приветствии не может быть создан.
1.1 Аналогия null из реального мира
Думая об аналогии с реальным миром, вы можете представить себе переменную как коробку. Точно так же, как переменная может содержать объект, коробка может содержать некоторые предметы, например, чайник.
Но допустим, что вы получаете коробку, открываете ее… а там ничего! Кто-то ошибся и отправил вам пустой ящик. Коробка ничего не содержит или, иначе говоря, содержит значениеnull
.
2. Проверка значения переменной на null
Хороший способ проверить содержит ли значение какой-либо переменной null
— использовать оператор строгого равенства :
const missingObject = null; const existingObject = { message: 'Hello!' }; missingObject === null; // => true existingObject === null; // => false
Соответственно инструкция missingObject === null
оценивается как true
, так как переменная missingObject
содержит значение null
.
Если переменная содержит ненулевое значение, например, объект, то инструкция existingObject === null
оценивается как false
.
2.1 null — это ложное значение (false)
null
наряду с false
, 0
, ''
, undefined
, NaN
, оцениваются условными операторами как ложные значения false
. Если в выражениях с условными операторами встречается одно из этих значений, то JavaScript оценивает его как false
.
Boolean(null); // => false if (null) { console.log('null is truthy'); } else { console.log('null is falsy'); // logs 'null is falsy' }
2.2 Тип null
Оператор typeof value
определяет тип значения. Например, результатом выполения инструкции typeof 15
является 'number'
, а результатом выполнения typeof { prop: 'Value' }
будет 'object'
.
Интересно, каков будет результат следующей инструкции кода: type null
?
typeof null; // => 'object'
Хм… как можно определить тип отсутствующего объектакак 'object'
? Оказывается, typeof null
это тоже 'object'
, что является следствием ошибки в ранней реализации языка JavaScript.
Не используйте оператор typeof
для определения значения типа null
. И как упоминалось ранее, используйте для этого оператор строгого равенства myVar === null
.
Если вы хотите проверить, содержит ли переменная объект с помощью оператора typeof
, то необходимо также предусмотреть проверку на присутствие значения null
:
function isObject(object) { return typeof object === 'object' && object !== null; } isObject({ prop: 'Value' }); // => true isObject(15); // => false isObject(null); // => false
3. Ловушка null
Значение типа null
может неожиданно появиться, в тех случаях, когда вы ожидаете объект. И далее, если вы попытаетесь получить значение какого-либо свойства объекта из значения null
, то интерпретатор JavaScript выдаст ошибку.
Давайте снова воспользуемся функцией greetObject()
и попробуем получить доступ к свойству message
у возвращенного объекта:
let who = ''; greetObject(who).message; // throws "TypeError: greetObject() is null"
Поскольку переменная who
является пустой строкой, то функция возвращает в качестве значения null
. При доступе к свойству message
у null
соответственно получаем ошибку типа TypeError.
Обычно для того, чтобы избежать такого эффекта используются два альтернативных варианта, которые мы рассмотрим в следующем разделе.
4. Альтернативы использованию null
И хотя очень заманчиво возвращать значение null
в том случае, если вы не можете по той или иной причине создать объект, но у этой практики есть существенные недостатки.
Как только значение null
появляется в вашем стеке выполнения, то вы обязательно должны проверять его присутствие.
При написании кода я стараюсь не возвращать в функциях null
, а вместо этого:
- возвращать вместо
null
объект по умолчанию; - генерировать вместо возврата
null
исключение соответствующего типа.
Давайте вернемся к функции greetObject()
, возвращающей объект с информацией о приветствии. Вместо возврата null
в случае отсутствия при ее вызове значения аргумента, мы можем вернуть объект по умолчанию следующим образом:
function greetObject(who) { if (!who) { who = 'Stranger'; } return { message: `Hello, ${who}!` }; } greetObject('Eric'); // => { message: 'Hello, Eric!' } greetObject(); // => { message: 'Hello, Stranger!' }
Либо возбуждать исключение с выводом соответствующего сообщения об ошибке:
function greetObject(who) { if (!who) { throw new Error('"who" argument is missing'); } return { message: `Hello, ${who}!` }; } greetObject('Eric'); // => { message: 'Hello, Eric!' } greetObject(); // => throws an error
Рассмотренные практики написания кода позволяют вам не использовать null
вообще, и избежать проблем с отладкой и сопровождением вашего кода в будущем.
5. null vs undefined
undefined
— соответствует значению неинициализированной переменной или свойства объекта.
Например, если вы объявляете переменную без присвоения начального значения, то результатом операции доступа к ее значению переменной будет undefined
:
let myVariable; myVariable; // => undefined
Основное различие между null
и undefined
заключается в том, что значение null
интерпретируется как отсутствие в качестве значения некоторого объекта, а — undefined
как неинициализированное состояние переменной или возвращаемого значения.
Использование оператора строгого равенства позволяет ===
позволяет различать значения null
и undefined
:
null === undefined; // => false
В то время как оператор нестрогого равенства==
определяет, что null
и undefined
эквивалентны:
null == undefined; // => true
Использование оператора нестрого равенства для проверки, содержит ли переменная null
или undefined
приведет к получению следующего результата:
function isEmpty(value) { return value == null; } isEmpty(42); // => false isEmpty({ prop: 'Value' }); // => false isEmpty(null); // => true isEmpty(undefined); // => true
6. Заключение
null
— специальное значение, реализованное в языке JavaScript, которое соответствует отсутствию объекта, который ожидается в качестве значения переменной или должен возвращаться функцией.
Оператор строгого равенства позволяет определить содержится ли в переменной null
: variable === null
.
Оператор typoef
полезен для определения типа переменной (число, строка, логическое значение). Однако его использование вводит в заблуждение в случае появления значения null
, так как результатом выполнения инструкции typeof null
будет 'object'
.
Значения null
и undefined
в какой-то степени эквивалентны, тем не менее, null
представляют собой отсутствующее значение типа объект, а undefined
неинициализированное состояние переменной или значения возвращаемого функцией.
По возможности избегайте возврата из ваших функций значений null
, а также установки значения переменных в null
. Такая практика приводит к распространению значений типа null
и необходимости проверок на null
. Вместо этого попробуйте использовать техники с возвратом функцией объекта со свойствами по умолчанию или даже возбуждения исключения, соответствующего типа.
А какое условие вы используете для проверки на null
?