Почему именно здесь условие оценивается как true?
var condition = new Boolean(false);
if (condition == !condition)
alert("The more you know...");
Почему именно здесь условие оценивается как true?
var condition = new Boolean(false);
if (condition == !condition)
alert("The more you know...");
Разбить его:
var condition = new Boolean(false);
Это фактически объект, а condition.valueOf() === false
!{}
оценивается как false, поскольку {}
истинно (объяснено http://www.ecma-international.org/ecma-262/5.1/#sec-9.2)
Итак, проверка condition.valueOf() == false
, которая истинна
Вы сравниваете объект (LHS) с булевым false
(RHS).
[object Boolean] == false
Оператор ==
выполняет принуждение типа в соответствии с алгоритмом сравнения абстрактного равенства, определенным ECMAScript. 11.9.3 Алгоритм сравнения абстрактного равенства
В соответствии с вашим кодом следующая точка этого алгоритма (где x - LHS, а y - RHS).
7) Если тип (y) является логическим, верните результат сравнения x == ToNumber (y).
Обратите внимание, что он сначала пытается преобразовать логическое значение в число. false
boolean преобразуется в число 0
, так что теперь мы имеем это:
[object Boolean] == 0
Как вы можете видеть, он рекурсивно вводит один и тот же алгоритм из-за ==
. Итак, теперь мы сравниваем объект с номером, и поэтому применяется следующая точка:
9) Если тип (x) - это объект и тип (y) - это строка или номер, возвращает результат сравнения ToPrimitive (x) == y.
Итак, теперь он пытается принудить объект к его примитивному значению. От 9.1 ToPrimitive при вызове объекта:
Объект Возвращает значение по умолчанию для объекта. Значение по умолчанию для объекта извлекается, вызывая внутренний метод [[DefaultValue]] объекта, передавая необязательный подсказку PreferredType. Поведение внутреннего метода [[DefaultValue]] определяется этой спецификацией для всех собственных объектов ECMAScript в 8.12.8.
Итак, вы можете видеть, что он хочет [[DefaultValue]]
объекта. Это приводит нас к 8.12.8 [[DefaultValue]], где он ожидает "подсказки". Поскольку он не получил "подсказки", он ведет себя так, как будто намек был "Number".
Когда внутренний метод [[DefaultValue]] из O вызывается без подсказки, он ведет себя так, как будто намек был Number,...
И это приводит нас к следующему поведению:
Когда вызывается внутренний метод O [[DefaultValue]] с номером подсказки, выполняются следующие шаги:
Пусть valueOf является результатом вызова внутреннего метода объекта [[Get]] объекта O с аргументом "valueOf".
Если IsCallable (valueOf) истинно, то
а. Пусть val является результатом вызова внутреннего метода [[Call]] значенияOf, с O как это значение и пустым списком аргументов.
б. Если val является примитивным значением, верните val.
И поэтому он вызывает метод .valueOf()
объекта, доведя нас до 15.6.4.3 Boolean.prototype.valueOf()
Пусть B - это значение.
Если тип (B) является логическим, то пусть b - B.
Иначе, если Type (B) - это Object, а значение внутреннего свойства [[Class]] в B - "Boolean", то пусть b является значением внутреннего свойства [[PrimitiveValue]] для B.
Просто введите исключение TypeError.
Возврат b.
Итак, с шага 3 вы можете увидеть, что он вернет объект [[PrimitiveValue]]
объекта. Это приводит нас к 15.6.2.1 новому булевому (значение)
Внутреннее свойство [[PrimitiveValue]] для вновь созданного булева объекта установлено в ToBoolean (значение).
Итак, вы можете увидеть, что вы, наконец, получите значение ToBoolean
значения, которое вы первоначально передали конструктору, который был false
. Его значение ToBoolean
, очевидно, false
, поэтому теперь ваше сравнение таково:
false == 0
Поскольку типы все еще не совпадают, в исходном алгоритме он перейдет к пункту 6:
6) Если тип (x) является логическим, верните результат сравнения ToNumber (x) == y.
Итак, теперь он хочет преобразовать логическое false
в число. Это похоже на то, что было сделано выше. Значение false
преобразуется в значение 0
, поэтому теперь мы имеем:
0 == 0
И, наконец, мы сравниваем сравнение по типу, и поэтому оно ведет себя так же, как и его строгая копия ===
, путем сравнения значений. И, очевидно, 0
делает равным 0
, поэтому мы получаем true
.
Мораль истории... это то, что вы получаете, когда задаете "почему" в JavaScript.
Это действительно помогает просто прочитать спецификацию, где это логически выложено, см.
Начните с:
var x = new Boolean(false);
var y = !x;
Тогда
y = false;
Поскольку логический объект не считается булевым, но вечным объектом, ToBoolean(x)
оценивается как true
и !true
оценивается как false
Алгоритм сравнения абстрактного равенства
Раунд 1: шаг 7
Если тип (y) булев, верните результат сравнения x == ToNumber (у).
y = 0; //ToNumber(false) is 0
Раунд 2: шаг 9
Если Type (x) - это Object и Type (y) - либо String или Number, return результат сравнения ToPrimitive (x) == y.
x = false //Basically ends up calling x.valueOf()
Раунд 3: Шаг 6
Если Type (x) является логическим, верните результат сравнения ToNumber (x) == y.
x = 0; //ToNumber(false) is 0
Наконец: Шаг 1
Если Type (x) совпадает с типом (y), то
Шаг 1 C
Если Type (x) - Number, то
Шаг 1 C iii
Если x - это то же значение числа, что и y, верните true.
Одна вещь, которую я узнал из Алгоритм сравнения абстрактного равенства, забудьте интуицию и выполните следующие шаги.
Поскольку объекты правдивы, их отрицание false
, поэтому в алгоритм входит следующее:
Boolean(false) == false
Если вы шаг за шагом, вы получите:
Boolean(false) == 0 // Step 7
false == 0 // Step 9
0 == 0 // Step 6
true