Чому `null> = 0 && null <= 0`, але не` null == 0`?


142

Мені довелося написати процедуру, яка збільшує значення змінної на 1, якщо її тип є, numberі присвоює 0 змінній, якщо ні, де початкова змінна nullабо undefined.

Перша реалізація полягала в v >= 0 ? v += 1 : v = 0тому, що я вважав, що що-небудь не число зробить арифметичний вираз помилковим, але це було неправильним, оскільки null >= 0його оцінюють як істинне. Тоді я дізнався, що nullповодиться як 0, і наступні вирази оцінюються як істинні.

  • null >= 0 && null <= 0
  • !(null < 0 || null > 0)
  • null + 1 === 1
  • 1 / null === Infinity
  • Math.pow(42, null) === 1

Звичайно, nullне 0. null == 0оцінюється як хибне. Це робить начебто тавтологічний вираз (v >= 0 && v <= 0) === (v == 0)помилковим.

Чому дорівнює null0, хоча насправді це 0?


3
Він говорить про Javascript. Ваш приклад - у PHP. У PHP-операторі == по-особливому порівнює значення. Ви можете зробити кілька справді божевільних порівнянь на зразок "10" == "1e1" (що правда). Якщо ви використовували оператор ===, ви отримаєте зовсім інший результат, оскільки він перевіряє відповідність типу, а також значення. Перевірте це посилання: php.net/manual/en/language.operators.comppare.php
Pijusn

Оператор PHP '==' дійсно працює "особливим" чином.
Двобітовий алхімік

Якщо ваша вимога полягала в тому, щоб почати рахувати з 1, а не з 0, існує дійсно короткий шлях до збільшення лічильників, які спочатку є nullабо undefined:c = -~c // Results in 1 for null/undefined; increments if already a number
Ates Goral

1
undefined- значення змінної для змінних, які не були ініціалізовані. null, з іншого боку, це порожнє значення об'єкта, і його не слід змішувати з цифрами. nullне слід поєднувати з числами, тому null не повинен поводитись як числа.
Метью

1
@AtesGoral - короткий, але неочевидний. Варто нагадати людям, що коли роблять щось не очевидне, будь ласка, додайте коментар із поясненням того, що робить код. У більшості ситуацій я вважаю це "передчасною оптимізацією", враховуючи, що вона торгує чіткістю для мінімального підвищення продуктивності.
ToolmakerSteve

Відповіді:


207

Наче ваше справжнє запитання:

Чому:

null >= 0; // true

Але:

null == 0; // false

Що насправді відбувається, це те, що Оператор « Більше, ніж» або «Рівний» ( >=) виконує примус типу ( ToPrimitive), з типом підказкиNumber , насправді всі реляційні оператори мають таку поведінку.

nullобробляється особливим чином Оператором рівних ( ==). У короткому, це тільки примушує до undefined:

null == null; // true
null == undefined; // true

Значення таких як false, '', '0', і[] підлягають числовий тип примусу, всі вони примушують до нуля.

Внутрішні деталі цього процесу можна побачити в Алгоритмі порівняння абстрактних рівностей та Алгоритмі абстрактного реляційного порівняння .

Підсумок:

  • Реляційне порівняння: якщо обидва значення не типу String, ToNumberвикликається обома. Це те саме, що додавати +спереду, що для нульових примусів до 0.

  • Порівняння рівності: дзвінки лише ToNumberдля рядків, чисел та булевих значень.


1
Привіт CMS, згідно з вашим поясненням нульовий примітив дорівнює 0, тому 0> = 0 повертає true і == повертає false.but за алгоритмом ecma Якщо Type (x) є Object, а Type (y) - або String або Number, повернути результат порівняння ToPrimitive (x) == y.then в цьому він повинен повернути true.Поясніть мені
bharath muppa

мені відповідь не дає відповіді - null is treated in a special way by the Equals Operator (==). In a brief, it only coerces to undefined:- і що? Чи можете ви пояснити, чому null >= 0? :)
Андрій Дейнеко

@bharathmuppa @ andrey-deineko: Решта відповіді CMS знаходиться тут: Алгоритм абстрактного порівняльного порівняння, який пояснює в пункті 3. що якщо обидва значення не вводять String, ToNumber викликається обома. Це те саме, що додавати +спереду, що для нульових примусів до 0. Рівність викликає лише ToNumber на рядках, числах і булевих номерах.
Майкл Лікори

7
Хороший опис, але мені це не подобається. У будь-якій мові (x == 0 || x> 0) має бути еквівалентно (x> = 0). javascript - дурна мова.
Джон Генкель

1
Це просто помилка в специфікації дійсно (тому що математично це неправильно), і з цим нічого робити, оскільки мільйони веб-сайтів покладаються на нульові порівняння ^^ '
mahieddine

14

Я хотів би розширити це питання для подальшого покращення наочності проблеми:

null >= 0; //true
null <= 0; //true
null == 0; //false
null > 0;  //false
null < 0;  //false

Це просто не має сенсу. Як і людські мови, ці речі потрібно вивчити напам’ять.


1
Як описано вище , це можна пояснити з допомогою лише як винятки , як == лікує нуль, в іншому випадку у всіх випадках нуль перетворюється в 0 за допомогою номера (nulll)
Sourabh Ранка

5

У JavaScript є суворі порівняння та перетворення типів

null >= 0; це правда, але (null==0)||(null>0) неправда

null <= 0; це правда, але (null==0)||(null<0) неправда

"" >= 0 також правда

Для реляційних абстрактних порівнянь (<=,> =) операнди спочатку переходять до примітивів, потім до того ж типу перед порівнянням.

typeof null returns "object"

Коли type is object javascript намагається впорядкувати об'єкт (тобто null), виконуються наступні кроки ( ECMAScript 2015 ):

  1. Якщо PreferredTypeне пройшов, нехайhint буде "за замовчуванням".
  2. Інше, якщо PreferredTypeце hintString, нехай hintбуде "string".
  3. Інше PreferredType- hintчисло, нехай hintбуде "число".
  4. Нехай exoticToPrimбуде GetMethod(input, @@toPrimitive).
  5. ReturnIfAbrupt(exoticToPrim).
  6. Якщо exoticToPrimце не визначено, то
    а) Нехай результат буде Call(exoticToPrim, input, «hint»).
    б) ReturnIfAbrupt(result).
    c) Якщо Type(result)немає об'єкта, поверніть результат.
    г) Киньте виняток TypeError.
  7. Якщо hint"за замовчуванням", нехай hintбуде "число".
  8. Повернення OrdinaryToPrimitive(input,hint).

Дозволені значення для підказки - "за замовчуванням", "число" та "рядок". Об'єкти дати є унікальними серед вбудованого об'єкта ECMAScript тим, що вони трактують "за замовчуванням" як еквівалент "рядку". Всі інші вбудовані об'єкти ECMAScript трактують "за замовчуванням" як "число" . ( ECMAScript 20.3.4.45 )

Тому я думаю, що nullперетворює на 0.


1

У мене була така ж проблема !!. Наразі єдине моє рішення - відокремитись.

var a = null;
var b = undefined;

if (a===0||a>0){ } //return false  !work!
if (b===0||b>0){ } //return false  !work!

//but 
if (a>=0){ } //return true !

Це може бути ясніше замість робити: if (a!=null && a>=0). Це пояснює причину того, що він не просто робить >=сам: "a може бути нульовим (або невизначеним, що також" == null ")".
ToolmakerSteve

0
console.log( null > 0 );  // (1) false
console.log( null == 0 ); // (2) false
console.log( null >= 0 ); // (3) true

Математично це дивно. В останньому результаті зазначено, що "нуль більший або дорівнює нулю", тому в одному з порівнянь вище це повинно бути правдою, але вони обидва помилкові.

Причина полягає в тому, що перевірка рівності ==та порівняння > < >= <=працюють по-різному. Порівняння перетворюють нуль у число, трактуючи його як 0. Ось чому (3) null >= 0є trueі (1) null > 0є false.

З іншого боку, перевірка рівності ==для undefinedі nullвизначається таким чином, що без будь - яких перетворень, вони дорівнюють один одному і не рівні нічого іншого. Ось чому (2) null == 0є false.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.