Как происходит принуждение типа, когда [] == false?

ECMA script документация говорит в абстрактном сопоставлении равенства alogorithm, что

Если тип (y) булев, верните результат сравнения x == ToNumber (у).

Так, например, [] == false будет принудительно, как,

1.   [] == Number(false)
2.   [] == 0 //comparison happens here.

Мой вопрос в том, что принуждение будет происходить рекурсивно, пока оба операнда не станут примитивными или нет? Как именно здесь происходит принуждение?

Я предполагаю, что принуждение будет повторяться до тех пор, пока преобразование двух операндов в примитивные, как показано ниже

1.   [] == Number(false)
2.   [] == 0
3.   ToPrimitive([]) == 0
4.   0 == 0 
5.   true

Является ли моя презумпция истиной? Если кто-нибудь не может объяснить, что здесь не так? Также как я могу проверить, что результат ToPrimitive([]) равен 0 в любой консоли браузера?

Ответ 1

Обратитесь к spec, [] == false можно разобрать, как показано ниже:

ToNumber(ToPrimitive([])) == ToNumber(false)

Подробнее...

Если тип (y) является логическим, верните результат сравнения x == ToNumber (y)

[] == ToNumber(false)

Если Type (x) - Object и Type (y) - либо String, Number, либо Symbol, то верните результат сравнения ToPrimitive (x) == y

ToPrimitive([]) == 0

В соответствии с алгоритмом ToPrimitive сначала вызывается valueOf. Но так как это возвращает объект, а не примитивное значение, toString будет вызываться во-вторых, который возвращает строку '', пустую строку

Если Type (x) - String и Type (y) - Number, верните результат сравнения ToNumber (x) == y

ToNumber('') == 0

Затем после ToNumber до 0. Сравнение с ToNumber(false) также равно 0. В результате они одинаковы.

Ответ 2

В спецификации указано

Если тип (y) булев, верните результат сравнения x == ToNumber (y).

Итак, да, это означает, что Abstract Equality Comparison будет вызываться рекурсивно до тех пор, пока он не вернет true или false или пока не появится ошибка. Одно из них произойдет в конечном итоге, поэтому гарантируется завершение рекурсии.

Шаг за шагом, это

[] == false;
[] == +0; // ToNumber(false)
"" == +0; // ToPrimitive([])
+0 == +0; // ToNumber("")
true;

Обратите внимание, что рекурсия не заканчивается, если оба операнда являются примитивами. Например, когда вы сравниваете два объекта, рекурсия отсутствует. Или когда вы сравниваете два примитива разных типов, может быть рекурсия.

И ToPrimitive([]) есть "", а не +0. Это потому, что

  • Массивы не имеют @@toPrimitive метода, поэтому вместо этого используется OrdinaryToPrimitive
  • Абстрактное равенство не дает никакого намека, поэтому используется Number
  • Затем valueOf (унаследовано от Object.prototype) вызывается первым, но не возвращает примитив.
  • Наконец toString (унаследовано от Array.prototype) - последняя попытка. Он выполняет join, который возвращает пустую строку в этом случае. Это примитив.