3

Столкнулся с таким нюансом, что if и конструкция var== false/true выдают разные результаты. Пожалуй, код продемонстрирует лучше слов:

if ({} && []) {
    console.log(({} && []) == true); // сработает и выведет false
}

То есть выражение {} && [] в конструкции if ведёт себя как true. Но при явном применении оператора сравнения говорит, что это не так. И я нигде не могу найти объяснения, которое бы меня удовлетворило. Другой показательный пример:

var c = new Boolean(false);
if(c) {// == true - не сработает
    console.log("8))))");
    console.log(c==false);
}

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

Единственная нить с одного из них, за которую я зацепился - это valueof. Якобы при == происходит численное сравнение, а не логическое, а за преобразование самого объекта в число отвечает именно valueOf. Но в описании самого valueOf я не нашел никакой четкой информации, кроме как той, что если он не переопределен, то наследуется от Object - но какая его реализация у Object? Какие правила? Почему, например, [2] == false, как [], а [1] == true?

Наткнулся так же на такую таблицу https://dorey.github.io/JavaScript-Equality-Table/ Она хоть и хороша, но похоже, составлена методом тыка и не даёт, ответа, что, почему и откуда берутся именно эти значения.

Александр
  • 1,978
  • 1
  • 16
  • 25
  • 1
    Оно ведёт себя не как true, а как truthy значение, которое считается истинным в условиях. Массив считается истинным, но при этом он совершенно не обязан быть равным true – andreymal Nov 25 '19 at 23:43
  • Вообще, если я правильно помню, любой непримитивный объект считается истинным, поэтому new Boolean(false) тоже считается истинным, в то время как false это примитив, который истинным уже не считается – andreymal Nov 25 '19 at 23:44
  • @andreymal , с thruthy более менее понятно. Мне как-то собой разумеющееся, что {} будет вести себя как true, тк это объект (и в интернете про такое поведение в основном). У меня больше вызывает вопрос, почему он может быть не равен примитивному типу true? – Александр Nov 25 '19 at 23:55
  • 1
    А с == всё сложно, вот тут есть таблица приведений типов. Если я правильно понимаю, массив приводится сперва к строке, а потом к числу, поэтому []==false (пустой массив→пустая строка→0==false) и [0]==false по той же логике (массив→"0"→0), но при этом [1]==true (true приводится к числу 1, false к числу 0) – andreymal Nov 25 '19 at 23:56
  • Не согласен, что это дубликат, разве что по названию. По ссылке речь о примитивных типах, у меня же примеры с объектами, и ответы той ветки не покрывают, как, например [] или даже [2] приводится к false, (а [1] почему-то true) – Александр Nov 26 '19 at 01:18
  • @Александр, в ответе приведен алгоритм, что к чему приводится в какой момент, а так же что именно происходит с условием в if – Grundy Nov 26 '19 at 08:25

1 Answers1

0

Логический оператор && возвращает правое значение, если левое истина, то есть оператор if некорректно сравнивать с (), которое возвращает полученный результат, в данном случае ({} && []) вернет пустой массив объект и сравнивать его с истиной тоже некорректно. Оператор if преобразует выражение к логическому типу и если выражение равно 0, пустой строке "", null, undefined и NaN, то результат становится false, иначе истина.

Max
  • 543
  • 2
  • 9
  • Спасибо за уточнение по &&, но оператор && тут не играет существенной роли. Можно взять отдельно [] и {} или даже [2,4] и {a:5}, ситуация не поменяется. С if они все вернут true, а с оператором == вернут false – Александр Nov 26 '19 at 01:29
  • Потому что оператор if преобразует выражение к логическому типу, а оператор == просто сравнивает. Оператор if работает примерно вот так, на примере пустого объекта массива []: ([] !== 0 && [] !== "" && [] !== null && [] !== undefined && [] !== NaN) – Max Nov 26 '19 at 01:45
  • да с if все ясно. Как сравнение-то работает? Например, почему [1]==true, а [2]==false. Почему {a:4}==false? – Александр Nov 26 '19 at 05:02
  • потому что такое == сравнение использует преобразование к числовому значению аналогично Number([1]) даст 1, и Number(true) даст 1, поэтому 1==1, в то время как Number([2]) даст 2, и Number(false) даст 0, получается не равенство 2!=0. Поэтому нужно в таких случаях использовать строгое сравнение без преобразования типов === в число, для корректного сравнения. – Max Nov 26 '19 at 05:25
  • вот подобное объяснение я находил, но остаётся вопрос: неравенство 2!=0 выдаст false, почему тогда 2==false? – Александр Nov 26 '19 at 05:39
  • неравенство 2!=0 выдает true, потому что 2 не равно 0, - "все верно". А равенство 2==false выдает false, потому что 2 не равно 0, - "не верно". – Max Nov 26 '19 at 05:47
  • странно, по такой логике 1!=0, значит должно быть 1==false, но это не так – Александр Nov 26 '19 at 06:16
  • Не понимаю о чем это. в 1 условии) 1 не равен 0 - результат истина, 2 условие) 1 равен 0 - результат ложь. Вполне логично – Max Nov 26 '19 at 06:21
  • Почитал про The Abstract Equality Comparison Algorithm

    в es5.1, там многие ответы есть в принципе. Вы, видимо, правы насчёт Number([]). А преобразование, 2==false и 1==true исходит из преобразования Number(bool), но все равно не до конца понимаю, почему 2== false...

    – Александр Nov 26 '19 at 06:25
  • 1
    ...но все равно не до конца понимаю, почему 2== false... , потому что идет сравнение числа 2 и 0, это два разных числа, поэтому результат ложь, если сравнить 1 == true будет результат истина, потому что будет сравнение 1 и 1, если сравнить 2 == true, то результат будет ложь, потому что сравниваются числа 2 и 1, они не одинаковые. – Max Nov 26 '19 at 06:28
  • А сравнение с помощью == любого объекта с истиной или ложью, в любом случае выдаст результат ложь, потому что Number({}) вернет абстрактное значение NaN, которое является так сказать изначальным значением, и сравнение этого значения с любым числом, выдаст результат ложь. Тоесть NaN это и не 0 и не 1, это нечто другое. – Max Nov 26 '19 at 06:36
  • @Max, на счет сравнение с помощью == любого объекта с истиной или ложью, в любом случае выдаст результат ложь: https://jsfiddle.net/5mxne92w/ – Grundy Nov 26 '19 at 08:29
  • @Max , в принципе так, спасибо. Я готов принять ваш ответ, если вы перенесете туда алгоритм ==false/true сравнений, который описали в комментариях, поскольку вопрос был о работе оператора сравнения с булевым значением – Александр Nov 26 '19 at 08:36
  • @Grundy мне кажется, про объекты - не совсем корректное утверждение, ведь [1] - тоже объект, но он будет ==true – Александр Nov 26 '19 at 08:38
  • @Александр, по ссылке на fiddle в моем комментарии можно увидеть что и для литерала объекта это утверждение не верно – Grundy Nov 26 '19 at 08:42