Чому в JavaScript чому "0" дорівнює false, а коли тестується "if", воно не відповідає false?


232

Нижче показано, що "0"в JavaScript невірно:

>>> "0" == false
true

>>> false == "0"
true

То чому ж друкується наступне "ha"?

>>> if ("0") console.log("ha")
ha

47
"0"є рядком, і оскільки він не порожній, він оцінюється як істинний.
Цифровий літак

8
"0" === false [...] false

3
Ознайомтеся з правдою статті статті Ангеса Кролла в JavaScript. javascriptweblog.wordpress.com/2011/02/07/…
timrwood

8
'0'==falseале "0" не є фальсифікованим значенням (так, Javascript може бути дивним)
Linsey

5
@Linsey: Уся річ "хибної" та "неправдоподібної" речі колись була призначена лише для пояснення того, як значення перетворюються на булі. Якщо порівнювати два значення з ==, вони ніколи не перетворюються на булеві, тому це не застосовується. (Правила перетворення, здається, сприяють перетворенню на числа.)
Мілімооз

Відповіді:


251

Причина полягає в тому, що коли ви явно це робите "0" == false, обидві сторони перетворюються на числа, а потім проводиться порівняння.

Коли ви робите:, if ("0") console.log("ha")значення рядка тестується. Будь-яка не порожня рядок є true, а порожня - рядок false.

Дорівнює (==)

Якщо два операнди не одного типу , JavaScript перетворює операнди, то застосовується суворе порівняння. Якщо будь-який операнд є числом або булевим , операнди перетворюються на числа, якщо це можливо; інакше, якщо будь-який операнд є рядком , інший операнд перетворюється на рядок, якщо це можливо. Якщо обидва операнди є об'єктами , то JavaScript порівнює внутрішні посилання, які рівні, коли операнди посилаються на один і той же об'єкт у пам'яті.

(Від операторів порівняння в мережі розробників Mozilla)


348

Таблиці, що відображають проблему:

truthy якщо твердження

і == truthy порівняння всіх типів об’єктів у JavaScript

Мораль використання історії === сувора рівність, що демонструє розум

Кредит на створення таблиці: https://github.com/dorey/JavaScript-Equality-Table


2
Це має набагато більше сенсу з іншого порядку значень gist.github.com/kirilloid/8165660
kirilloid

3
Відтепер, якщо хтось скаже, що він ніколи не використовує суворих операторів порівняння, я зіткнуся з ним за цими таблицями і змушу його плакати. Досі не впевнений, чи розумію я цю концепцію NaN. Я маю на увазі, typeof NaN // numberале NaN === NaN // false, гм ...
Юстус Ромінь

4
Мій друг зробив f.cl.ly/items/3b0q1n0o1m142P1P340P/javascript_equality.html - ті ж графіки, що і вище, але трохи легше читати.
Люсі Бейн

@JustusRomijn є декілька значень для представлення NaN, тому, коли ви порівнюєте 2 NaN, вони мають різні значення (я думаю). Прочитайте першу цитату тут .
cychoi

4
Ці таблиці мають помилку. Ні , ==ні ===оператор для [], {}, [[]], [0]і [1]значення не обчислюватися так. Я маю на увазі [] == []і [] === []також помилково.
Гербертуш

38

Це згідно спец.

12.5 Заява if 
.....

2. Якщо вірно ToBoolean (GetValue (exprRef)), то 
а. Поверніть результат оцінки першої заяви.
3. Ще, 
….

Відповідно до специфікації, ToBoolean є

Абстрактна операція ToBoolean перетворює свій аргумент у значення типу Boolean згідно таблиці 11:

І ця таблиця говорить про рядки:

введіть тут опис зображення

Результат помилковий, якщо аргументом є порожній рядок (його довжина дорівнює нулю); інакше результат правдивий

Тепер, щоб пояснити, чому "0" == falseви повинні прочитати оператор рівності, який стверджує, що він отримує своє значення, якщо абстрактна операція GetValue(lref)відповідає однаковій для правої частини.

Що описує цю відповідну частину як:

якщо IsPropertyReference (V), то 
а. Якщо HasPrimitiveBase (V) помилковий, то нехай get є внутрішнім методом бази [[Get]], інакше нехай отримує
бути спеціальним внутрішнім методом [[Get]], визначеним нижче. 
б. Поверніть результат виклику внутрішнього методу get, використовуючи base як його це значення, і передаючи
GetReferencedName (V) для аргументу

Або іншими словами, рядок має примітивну базу, яка викликає внутрішній метод отримання і виявляється помилковою.

Якщо ви хочете оцінити речі за допомогою операції GetValue ==, якщо ви хочете оцінити за допомогою функції ToBoolean, використовуйте ===(також відомий як "суворий" оператор рівності)


"a string has a primitive base, which calls back the internal get method and ends up looking false"Це правда для всіх рядків?
aziz punjani

@Interstellar_Coder Section 8.12.3: [[Get]] (P)описує, як це працює. Це справедливо лише для випадків, коли рядок дорівнює 0, оскільки це робить купу інших внутрішніх дзвінків, врешті-решт, в результаті GetOwnPropertyчого бачиться, що "все" - це властивість даних, яка потім повертає все це значення назад. Ось чому "0" помилково, а "бла" - істинно. Перегляньте кілька відео Дугласа Крокфорда про театр розробників Yahoo, він описує "truthyness" в JavaScript трохи менш складним, ніж я. Якщо ви зрозумієте, що означає "правда" та "хибність", ви зрозумієте відповідь Бобенса відразу.
інкогніто

1
Де я можу знайти специфікацію?
user985366

12

Це PHP, де рядок "0"є хибним (false-when-used-in-boolean-context). У JavaScript всі непусті рядки є правдоподібними.

Хитрість полягає в тому, що ==проти булевого значення не оцінюється в булевому контексті, він перетворюється на число, а у разі рядків, що робиться шляхом розбору як десятковий. Таким чином, ви отримуєте Номер 0замість булінів правдивості true.

Це дійсно поганий мовний дизайн, і це одна з причин, коли ми намагаємося не використовувати нещасного ==оператора. Використовуйте ===замість цього.


7
// I usually do this:

x = "0" ;

if (!!+x) console.log('I am true');
else      console.log('I am false');

// Essentially converting string to integer and then boolean.

4

Ваші цитати 0роблять це рядком, який оцінюється як істинний.

Видаліть цитати, і це повинно працювати.

if (0) console.log("ha") 

правильно, а не про те, як "змусити це працювати", але питання більше схоже на "чому він так поводився?"
неополярність

2

Це все через специфікації ECMA ... "0" == falseчерез правила, вказані тут http://ecma262-5.com/ELS5_HTML.htm#Section_11.9.3 ... І if ('0')оцінює справжнє через правила, вказані тут http: / /ecma262-5.com/ELS5_HTML.htm#Section_12.5


Я не знав, що хтось переніс специфікацію на сайт ... це приголомшливо! Більше не для мене файлів PDF.
інкогніто

1

Тести експресії "якщо" на істинність, у той час як подвійні рівні тести на незалежність від типу еквівалентності. Рядок - це завжди триут, як це вказували інші. Якби подвійне рівне тестувало обидва його операнди на правдивість, а потім порівнювало результати, то ви отримали б результат, який ви інтуїтивно припускали, тобто ("0" == true) === true. Як каже Дуг Крокфорд у своєму відмінному JavaScript: "Хороші частини" , "правила, за якими [== примушує типи його операндів] є складними і незабутніми .... Відсутність транзитивності насторожує". Досить сказати, що один з операндів примусований до типу, щоб відповідати іншому, і що "0" в кінцевому підсумку трактується як числовий нуль,


1

== Оператор рівності оцінює аргументи після перетворення їх у числа. Таким чином, рядок нульовий "0" перетворюється на тип даних номера, а булева помилка перетворюється на число 0. Отже

"0" == false // true

Те ж стосується `

false == "0" //true

=== Сувора перевірка рівності оцінює аргументи з оригінальним типом даних

"0" === false // false, because "0" is a string and false is boolean

Те саме стосується і

false === "0" // false

В

if("0") console.log("ha");

Рядок "0" не порівнює з жодними аргументами, а рядок - це справжнє значення до тих пір, поки воно не порівнюється з будь-якими аргументами. Це саме так

if(true) console.log("ha");

Але

if (0) console.log("ha"); // empty console line, because 0 is false

`


1

Це тому, що JavaScript використовує тип примусу в булевих контекстах та вашому коді

if ("0") 

буде примусово до істини в булевих контекстах.

У Javascript є й інші truthy значення, які будуть примусові до істинних у булевих контекстах, і таким чином виконати блок if:

if (true)
if ({})
if ([])
if (42)
if ("0")
if ("false")
if (new Date())
if (-42)
if (12n)
if (3.14)
if (-3.14)
if (Infinity)
if (-Infinity)

0
if (x) 

примушує x за допомогою внутрішнього JavaScript toBoolean (http://es5.github.com/#x9.2)

x == false

примушує обидві сторони, використовуючи внутрішній примус до Number (http://es5.github.com/#x9.3) або toPrimitive для об'єктів (http://es5.github.com/#x9.1)

Для отримання детальної інформації див. Http://javascriptweblog.wordpress.com/2011/02/07/truth-equality-and-javascript/

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