Обучающих статей, рассматривающих различия между null и undefined на просторах интернета столько, что, кажется, и int64 не хватит, чтобы их сосчитать. Так что вводные бла-бла-бла оставим за скобками и рассмотрим основные подводные камни, которые бросает нам под ноги undefined. Тертым калачам тут делать нечего, они все, о чем говорится ниже, и сами знают, разве что смогут подсказать еще какой пример в комментариях (приветствуется). Остальных приглашаю продолжить чтение. Эту проблему решают статические анализаторы и TypeScript, но помнить о ней все же стоит. Ничего военного: либо инициализируем значение сразу, либо контролируем, чтобы оно обязательно было задано до того, как начнем читать из переменной (анализатор в помощь). Если добавить в пример замыкание и асинхронный вызов, то все становится куда сложнее отследить: Пример выше — конечно, явная ошибка, нужно сперва дождаться инициализации a, а потом уже получать сумму. Тем не менее, на практике я подобных ошибок встречал немало, особенно у тех, кто еще не до конца понял принципы работы асинхронности. Примечание: Для удобства использован пример с сериализацией/десериализацией в JSON при помощи встроенных средств языка, однако стоит отметить, что подобное поведение может присутствовать в любом другом формате, поддерживающим опциональные поля. Возьмем очень простой объект, состоящий из трех полей (для удобства, структура объекта будет описана в виде интерфейса TypeScript): Теперь создадим объект, соответствующий интерфейсу выше: Конечно, можно было объявить еще короче, не указывая поле desc вовсе, но мы нарушим все рекомендации комитетов по стандартизации и сделаем по-своему. Давайте теперь обойдем объект в цикле по ключам: Результат: Прекрасно, теперь сериализуем его в JSON, передадим по сети, десериализуем и вновь выполним обход: Результат: Уппс! Погодите-ка, а куда же делось наше поле desc? Дело в том, что в JSON нет типа undefined, для него поле со значением undefined - это отсутствующее поле, если вывести значение serialized — получим следующий текст: При этом десериализованный объект (incoming) все еще соответствует интерфейсу SimpleObject, так как попытка получить значение поля desc в любом случае даст значение undefined: В 90% случаев все будет нормально и не будет являться проблемой ровно до той поры, пока мы не попытаемся произвести сравнение этих объектов. Создадим копию объекта obj и, при помощи lodash.isEqual сравним копию и десериализованный результат с оригиналом: Какая неприятная неожиданность! Эта неприятность может нас поджидать во многих случаях, например, если мы хотим сохранить сериализованное значение где-либо, а потом подгрузить и сравнить с текущим (redis, РСУБД, файл, localStorage). Решается тривиально: использовать null для значений полей вместо undefined. К сожалению, это возможно не всегда. Например, если удаленный ресурс вам не принадлежит и уже использует опциональные поля. В таком случае, банального isEqual будет уже недостаточно — придется добавить дополнительных проверок, либо добавлять undefined-поле сразу после десериализации сохраненного значения. Другими словами, требуется провести валидацию десериализованных данных. Тип Undefined явно лишний, гораздо логичней было бы выбрасывать исключение при попытке прочитать несуществующее поле или неинициализированную переменную, но Брендан Айк пошел по другому пути, впрочем, винить его за это сложно. Нам остается лишь помнить об этих особенностях при написании кода, либо перейти на другой язык (некоторая доля шутки). Благодарю за потраченное время. Ссылка на репозиторий с примерами. P.S.: Ничего не имею против минусов, но, пожалуйста, будьте добры пояснить - в чем именно заключается низкий технический уровень материала. Заранее, спасибо.