Извините за ответ на более старый вопрос, но причина, по которой вам нужны как неопределенные, так и нулевые значения, проста: в языке типизации утки на основе прототипа вы должны обязательно различать «этот объект не определяет значение для X» и «этот объект говорит, что X ничего / нуль / пусто».
Без этой возможности невозможно обойти цепочку прототипов, и поэтому наследование не может работать; Вы должны быть в состоянии определить, что obj.someProp не определен, чтобы вы могли смотреть на obj.prototype.someProp и далее вверх по цепочке, пока не найдете значение. Если obj.someProp вернул null, не было бы способа узнать, действительно ли он нулевой или просто означал «посмотрите на мой прототип». Единственный способ обойти это - добавить закулисную магию за кулисы, которая лишает вас способности размышлять с цепями прототипов и делать различные другие элементы черной магии JS.
Как и большая часть Javascript, идея undefined и null сначала кажется вонючей и глупой, а потом абсолютно блестящей (затем снова вонючей и глупой, но с разумным объяснением).
Такой язык, как C #, не будет компилироваться, если вы получите доступ к несуществующему свойству, а другие динамические языки часто выдают исключения во время выполнения, когда вы прикасаетесь к несуществующему свойству, что означает, что вы должны использовать специальные конструкции для их проверки. Плюс классы означают, что когда объект создается, вы уже знаете его цепочку наследования и все свойства, которыми он обладает - в JS я могу изменить прототип на 15 шагов вверх по цепочке, и эти изменения появятся в существующих объектах.
undefined
и когда использоватьnull