В JavaScript почему «0» равно false, но при проверке «if» само по себе оно не равно false?

232

Следующее показывает, что "0"это ложно в Javascript:

>>> "0" == false
true

>>> false == "0"
true

Так почему же печатается следующее "ha"?

>>> if ("0") console.log("ha")
ha
nonopolarity
источник
47
"0"является строкой, и поскольку она не пустая, она оценивается как true.
Цифровой самолет
8
"0" === false [...] false
3
Проверьте правду статьи Ангуса Кролла в javascript. javascriptweblog.wordpress.com/2011/02/07/…
Тимрвуд
8
'0'==falseно '0' не является ложным значением (да, Javascript может быть странным)
Линси
5
@Linsey: Вся эта «ложная» и «правдивая» вещь только когда-то предназначалась для объяснения того, как значения преобразуются в логические значения. Когда вы сравниваете два значения с ==, они никогда не преобразуются в логические значения, поэтому это не применяется. (Правила для конвертации, кажется, предпочитают конвертировать в числа.)
Миллимы

Ответы:

251

Причина в том, что когда вы явно делаете это "0" == false, обе стороны преобразуются в числа, и затем выполняется сравнение.

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

Равный (==)

Если два операнда не одного типа , JavaScript преобразует операнды, а затем применяет строгое сравнение. Если операнд является числом или логическим значением , операнды преобразуются в числа, если это возможно; иначе, если любой операнд является строкой , другой операнд преобразуется в строку, если это возможно. Если оба операнда являются объектами , тогда JavaScript сравнивает внутренние ссылки, которые равны, когда операнды ссылаются на один и тот же объект в памяти.

(От операторов сравнения в Mozilla Developer Network)

JDI
источник
348

Таблицы, отображающие проблему:

правдивое утверждение

и == правдивые сравнения всех типов объектов в 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)) равен true, тогда 
а. Вернуть результат оценки первого утверждения.
3. Остальное, 
....

ToBoolean, согласно спецификации, это

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

И эта таблица говорит о строках:

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

Результат равен false, если аргумент является пустой строкой (его длина равна нулю); в противном случае результат верен

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

Который описывает эту соответствующую часть как:

если IsPropertyReference (V), то 
а. Если HasPrimitiveBase (V) имеет значение false, пусть get будет внутренним методом [[Get]] для base, в противном случае пусть get
быть специальным внутренним методом [[Get]], определенным ниже. 
б. Вернуть результат вызова метода get internal с использованием base в качестве значения this и передачи
GetReferencedName (V) для аргумента

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

Если вы хотите оценить вещи, используя операцию GetValue, используйте ==, если вы хотите оценить, используя ToBoolean, используйте ===(также известный как «строгий» оператор равенства)

Инкогнито
источник
"a string has a primitive base, which calls back the internal get method and ends up looking false"Это правда для всех строк?
Азиз Пунджани
@Interstellar_Coder Section 8.12.3: [[Get]] (P)описывает, как это работает. Это верно только для случаев, когда строка GetOwnPropertyравна 0, так как она выполняет кучу других внутренних вызовов, в результате которых обнаруживается, что «что угодно» является свойством данных, которое затем полностью возвращает это значение. Вот почему «0» - ложь, а «бла» - правда. Посмотрите видео Дугласа Крокфорда на театре разработчиков Yahoo, он описывает «правдивость» в JavaScript чуть менее сложно, чем я. Если вы понимаете, что означает «правдивость» и «ложь», вы сразу поймете ответ Бобинса.
Инкогнито
1
Где я могу найти спецификацию?
user985366
12

Это PHP, где строка "0"ложная (false-when-used-in-boolean-context). В JavaScript все непустые строки являются достоверными.

Хитрость в том, что ==логическое значение не оценивается в логическом контексте, оно конвертируется в число, а в случае строк это делается путем анализа в виде десятичного числа. Таким образом, вы получите номер 0вместо истинности логического true.

Это очень плохой языковой дизайн, и это одна из причин, по которой мы стараемся не использовать неудачный ==оператор. Используйте ===вместо этого.

bobince
источник
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.
Thava
источник
4

Ваши кавычки вокруг 0делают это строкой, которая оценивается как истина.

Удалите цитаты, и это должно работать.

if (0) console.log("ha") 
Джейсон Дженнаро
источник
правильно, не о том, как "заставить это работать", но вопрос больше похож на "почему он так себя вел?"
неполярность
2

Это все из-за спецификаций ECMA ... "0" == falseиз-за правил, указанных здесь http://ecma262-5.com/ELS5_HTML.htm#Section_11.9.3 ... И if ('0')оценивается как true из-за правил, указанных здесь http: / /ecma262-5.com/ELS5_HTML.htm#Section_12.5

Нарендра Ядала
источник
Я не знал, что кто-то перенес спецификации на сайт ... это круто! Нет больше PDF-файлов для меня.
Инкогнито
1

Выражение «если» проверяет на правдивость, а двойное равенство - на независимость от типа. Строка всегда правдива, как отмечали другие. Если дважды равно испытывали оба операнда для truthiness и сравнение полученных результатов, то вы получите результат вы интуитивно предполагая, т.е. ("0" == true) === true. Как говорит Дуг Крокфорд в своем превосходном JavaScript: «Хорошие части» , «правила, по которым [== приводит типы своих операндов], сложны и не запоминаются… Отсутствие транзитивности вызывает тревогу». Достаточно сказать, что один из операндов приведен к типу для соответствия другому, и что «0» в конечном итоге интерпретируется как числовой ноль,

Jollymorphic
источник
1

== Оператор равенства оценивает аргументы после преобразования их в числа. Поэтому строка нулевой «0» преобразуется в тип данных Number и логическое значение FALSE преобразуется в число 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, которые будут приведены к true в логических контекстах, и, таким образом, выполнить блок 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

принуждает обе стороны, используя внутреннее приведение к toNumber (http://es5.github.com/#x9.3) или toPrimitive для объектов (http://es5.github.com/#x9.1)

Для получения полной информации см. Http://javascriptweblog.wordpress.com/2011/02/07/truth-equality-and-javascript/

AngusC
источник