null и undefined и их поведение в JavaScript - PullRequest
21 голосов
/ 09 августа 2011

Итак, после большого спора / обсуждения / обсуждения реализации null и undefined в javascript, я бы хотел, чтобы кто-то объяснил причины реализации и почему они отличаются в некоторых обстоятельствах.Некоторые конкретные моменты, которые меня беспокоят:

  • null == undefined оценивается как true
  • null + 1 равно 1, но undefined + 1 равно NaN
  • if(!null) оценивается как true и if(null) оценивается как false, но null == false оценивается как false.

Я прочитал спецификацию и знаю, как достигаются результаты, я ищупарадигмы и причины, которые диктуют эту спецификацию.Некоторые из этих пунктов, особенно второй, учитывая первый, кажутся очень противоречивыми.

Ответы [ 4 ]

11 голосов
/ 09 августа 2011

Короткая и приятная версия заключается в том, что JavaScript был разработан и реализован очень быстро командой Netscape, и в нем были некоторые несоответствия, такие как те, на которые вы указали.

Команда Internet Exploder сделала все возможное, чтобы скопировать JS точно , и чертовски хорошо поработала до такой степени, что несоответствия также были скопированы. Когда Netscape пошел на стандартизацию JS как ECMAScript, MS был частью этого и в основном сказал, что им не разрешено менять стандарт, потому что это нарушит старый код (инерция существующих систем). Несоответствия были стандартизированы, вот и все.

У Дугласа Крокфорда есть очень хорошая серия бесед о некоторых из этих проблем .

8 голосов
/ 09 августа 2011

В первую очередь , хотя множество языков не имеют двух методов для такой схожей цели, в Javascript они служат различным, хотя и несколько перекрывающимся целям. "Почему есть оба?" здесь уже спрашивали, и я обнаружил, что этот ответ объясняет это довольно хорошо. TL; DR : Javascript имеет определенные языковые функции, которые генерируют отсутствующие значения в отличие от неинициализированных значений:

  • delete значения d
  • несуществующие свойства в объекте
  • отсутствуют параметры функции

Что касается кажущихся противоречий в вашем вопросе, они на самом деле довольно легко объясняются спецификацией. (Полагаю, можно даже утверждать, что объяснение изящно, хотя, вероятно, есть те, кто категорически не согласен.)

Обращаясь к каждому по отдельности:

  • null == неопределенное значение равно true

См. этот ответ для лучшего объяснения этого. Короче говоря, спецификация сравнения абстрактных равенств говорит, что они (не строго) равны.


  • ноль + 1 равно 1, но не определено + 1 равно NaN

Оператор + работает либо как унарный оператор + (преобразование чисел), либо как оператор сложение , но оба маршрутизатора направляют аргументы в спецификацию ToNumber, который говорит:

Тип аргумента & mdash; Результат
Не определено & mdash; NaN
Null & mdash; + 0
Boolean & mdash; Результат равен 1, если аргумент верен. Результат равен +0, если аргумент равен false.
Номер & mdash; Результат равен входному аргументу (без преобразования).

Другими словами null + 1 становится +0 + 1, а undefined + 1 становится NaN + 1, что всегда NaN.


  • если (! Null) имеет значение true, а if (null) - false, а null == false - false.

Как вы знаете, ! - это оператор Logical Not , и он выполняет ToBoolean преобразование для выражения. Это тип усечения.

Оператор if (if (expr)) выполняет неявное логическое сравнение expr . Итак, взгляните на тип expr в обоих приведенных выше if утверждениях:

  • if (!null): expr равно !null, которое, учитывая результат логического оператора not (!), представляет собой логическое значение .
  • if (null): expr равно null, что означает, что преобразование не было выполнено.

Так как оператор не логический выполняет фактическое преобразование, то же самое происходит и в других случаях и на самом деле не является логическим противоречием, как вам кажется:

  • if (!"" == !undefined) = true
  • if ("" == undefined) = false , конечно.
4 голосов
/ 09 августа 2011

Их лучше всего рассматривать как совершенно разные объекты, используемые для разных целей:

null используется для «не имеет значения». Он используется языком довольно редко, но часто используется средой хоста для обозначения «нет значения». Например, document.getElementById возвращает null для несуществующих элементов. Точно так же свойство IE 100 onreadystatechange для HTMLScriptElement s установлено на null, а не undefined, чтобы показать, что, хотя свойство существует , в настоящее время не установлено . Обычно рекомендуется использовать null в своем собственном коде вместо undefined и оставлять undefined в следующих случаях:

undefined используется для «даже не установлен или даже не существует». Это «по умолчанию» во многих случаях, например, доступ к неопределенному свойству (например, onreadystatechange для HTMLScriptElement в браузерах, отличных от IE), возвращаемое значение по умолчанию из методов без операторов return, значение по умолчанию для параметров функции, когда функция вызывается с меньшим количеством аргументов, чем объявлено, и тому подобное.

Таким образом, полезно думать о null как о «допустимом значении», которое означает нечто особенное. Принимая во внимание, что undefined больше относится к языку.

Конечно, есть некоторые крайние случаи, когда эти рассуждения не совсем верны; это в основном по наследственным причинам. Но есть разница, и она имеет смысл.


Что касается ваших болевых точек, в частности, они в основном возникают из-за зла оператора == или принуждения типа:

  • null == undefined: не используйте оператор ==, потому что по сути это беспорядок в правилах обратной совместимости, которые в то время казались интуитивными.
  • null + 1 === 1 против undefined + 1 === NaN: оператор + выполняет приведение типа к Number перед вычислением. И null приводит к 0 (+null === 0), тогда как undefined приводит к NaN (isNaN(+undefined) === true).
  • if (!null), if (null), null == false: if оценивает «правдивость» или «ложность» своего аргумента, который не имеет ничего общего с беспорядком правил для ==. null - это обман, а !null - правда, но правила для == не позволяют null == false.
1 голос
/ 09 августа 2011

null == undefined действительно оценивается как true, но null === undefined оценивается как false.

Разница в этих двух утверждениях заключается в операторе равенства. Двойное равенство в Javascript преобразует два элемента в один и тот же тип перед их сравнением; для null == undefined это означает, что null преобразуется в неопределенную переменную перед выполнением сравнения, следовательно, равенство.

Мы можем продемонстрировать тот же эффект со строками и целыми числами: "12" == 12 верно, но "12" === 12 неверно.

Этот пример дает нам более простой способ обсудить ваш следующий пункт о добавлении одного к каждому из них. В приведенном выше примере добавление 1 к целому числу, очевидно, дает 13, но со строкой "12" + 1 дает нам строку "121". Это имеет смысл, и вам бы этого не хотелось, но с помощью оператора двойного равенства два первых значения были представлены как равные.

Урок здесь заключается в том, чтобы всегда использовать оператор тройного равенства вместо двойного равенства, если только у вас нет особой необходимости сравнивать переменные разных типов.

Ваш последний пункт демонстрирует переменчивую природу null в целом. Это своеобразный зверь, как скажет любой, кто когда-либо пытался работать с полем базы данных, обнуляемым. У Null есть очень специфическое определение в информатике, которое реализовано одинаково для нескольких языков, поэтому описанная вами ситуация не является особой странностью Javascript. Нуль странный. Не ожидайте, что оно будет вести себя как альтернативное имя для false, потому что это не работает таким образом. Встроенное значение infinity может вести себя так же странно и по тем же причинам.

Javascript имеет свою долю странности, хотя. Возможно, вам будет интересно прочитать http://wtfjs.com/,, в котором есть записи для целой загрузки странных вещей, которые делает Javascript. Многие из них связаны с null и undefined (знаете ли вы, что на самом деле можно переопределить значение встроенного объекта undefined ?!), и большинство из них приходят с объяснением того, как что на самом деле происходит и почему. Это может быть полезно, чтобы показать вам, почему все работает так, как они работают, и, безусловно, поможет вам показать, чего следует избегать! И если ничего другого, это делает хорошее развлекательное чтение, чтобы видеть некоторые из злоупотреблений, которые люди пытались бросить на плохой язык.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...