Подтвердить что ты не робот

Как 1 == [1] в javascript?

Недавно мне задали этот вопрос в интервью.

 var a = 1;
 var b = [1];

Что вернет a == b;.

Когда я проверил, что на моей консоли браузера Chrome я получил это.

var a = 1;
var b = [1];
a == b;
true

Я также проверил

var a = 1;
var b =(1);
a == b;
true

Я знаю, что b в массиве размером 1. Означает ли это, что размер массива присваивается b. Я действительно смущен. Может ли кто-нибудь объяснить мне логику?

4b9b3361

Ответ 1

Если объект сравнивается с числом или строкой, JavaScript пытается вернуть значение по умолчанию для объекта. Операторы пытаются преобразовать объект в примитивное значение, значение String или Number, используя valueOf и toString методы объектов. Если эта попытка конвертировать объект не выполняется, генерируется ошибка времени выполнения. Ref]

var a = 1;
var b = [1];
//What is happening when `(a==b)`
//typeof a;   ==> number
//typeof b;  ==>object
//Object is converted to Primitive using `valueOf` and `toString` methods of the objects
var val = b.valueOf().toString();
console.log('Values after conversion is: ' + val + '  And typeof converted value is:  ' + typeof val);
//typeof val; ==> string
//a == b; will be evaluated as `true` because `'1' == 1` hence..
console.log(a == b); //'1'==1 ==> true

Ответ 2

Я не понял из Района ответа, как valueOf и toString вступают в игру при преобразовании объекта в примитивное значение; поэтому я вник в спецификации ECMAScript 2015.

Предупреждение: длинный ответ.

Мы хотим проверить выражение 1 == [1].

Начиная с 12.10 операторов равенства, мы видим, что после извлечения значений выражений последний шаг

  1. Возвращает результат выполнения абстрактного сравнения равенства rval == lval

Абстрактное сравнение равенства определено в главе 7.2.12 Абстрактное сравнение равенства.

7.2.12 Абстрактное сравнение равенства Сравнение x == y, где x и y - значения, создает true или false. Такое сравнение выполняется следующим образом:

  • ReturnIfAbrupt (х).
  • ReturnIfAbrupt (у).
  • Если тип (x) совпадает с типом (y), то а. Верните результат выполнения строгого сравнения равенств x === y.
  • Если x равно null, а y - undefined, верните true.
  • Если x равно undefined, а y - null, верните true.
  • Если Type (x) - Number и Type (y) - String, верните результат сравнения x == ToNumber (y).
  • Если Type (x) - String и Type (y) - Number, верните результат сравнения ToNumber (x) == y.
  • Если тип (x) является логическим, верните результат сравнения ToNumber (x) == y.
  • Если тип (y) булев, верните результат сравнения x == ToNumber (y).
  • Если Type (x) является либо строкой, либо числом, либо символом, и типом (y) является Object, тогда вернуть результат сравнения x == ToPrimitive (y).
  • Если Type (x) - это Object и Type (y) - либо String, Number, либо Symbol, то верните результат сравнения ToPrimitive (x) == y.
  • Возвращает false.

Выражение 1 == [1] относится к случаю 10.
Поэтому в основном, как и ожидалось, массив [1] преобразуется в значение примитивного типа.

ToPrimitive определяет в 7.1.1 ToPrimitive (input [, PreferredType])

Абстрактная операция ToPrimitive принимает входной аргумент и необязательный аргумент PreferredType. абстрактная операция ToPrimitive преобразует свой входной аргумент в не-объектный тип.

Я не включил полную цитату, так как только интересный для этого примера:

  • Аргумент PreferredType (на самом деле hint var) преобразуется из "default" (поскольку он не передается) в "число".
  • OrdinaryToPrimitive вызывается с теми же аргументами.

Теперь интересная часть OrdinaryToPrimitive сделает следующее:

  • Assert: Type (O) - Object
  • Assert: Тип (подсказка) - это String, а его значение - "строка" или "число".
  • Если подсказка "строка", то а. Пусть methodNames - "toString", "valueOf" ".
  • Else,
    а. Пусть methodNames будут" "valueOf", "toString" ".
  • Для каждого имени в именах методов в списке, выполните а. Пусть метод Get (O, name).
    б. ReturnIfAbrupt (метод).
    с. Если IsCallable (метод) истинно, тогда... i. Пусть результат будет Call (метод, O).
    ... ii. ReturnIfAbrupt (результат).
    ... iii. ** Если Тип (результат) не Объект, верните результат. **
  • Выбросить исключение TypeError

Итак, чтобы преобразовать [1] в примитивное значение, среда выполнения сначала попросит позвонить valueOf. Этот метод возвращает сам массив, который является объектом, поэтому по 5.c.iii следующий метод toString.
 Этот метод возвращает элементы массива как список, разделенный запятыми, поэтому он просто возвращает строку "1".

Итак, мы сокращаем сравнение 1 == "1", которое по правилам абстрактного равенства, пункт 6, означает преобразование "1" в число 1 и выполнение тривиального сравнения 1 = 1.

С сомнительным читателем предлагается проверить, как Сравнение строгого равенства действительно определено в стандарте.


Вы можете играть с этими преобразованиями, чтобы лучше понять их, вот пример HTML файла игровой площадки

<html>
    <head><title>title</title></head>
    <body>
        <script>
            var old_valueOf = Array.prototype.valueOf;
            var old_toString = Array.prototype.toString;

            Array.prototype.valueOf = function(){ console.log("Array::valueOf"); return old_valueOf.apply(this); };
            Array.prototype.toString = function(){ console.log("Array::toString"); return old_toString.apply(this); };

            console.log(1 == [1]); //Array::valueOf, Array::toString, true 

            Array.prototype.valueOf = function(){ console.log("Array::valueOf"); return 2; };

            console.log(1 == [1]); //Array::valueOf, false 

            Array.prototype.valueOf = function(){ console.log("Array::valueOf"); return {}; };
            Array.prototype.toString = function(){ console.log("Array::toString"); return {} };

            console.log(1 == [1]); //Array::valueOf, Array::toString, Uncaught TypeError: Cannot convert object to primitive value
        </script>
    </body>
</html>

Ответ 3

Это связано с типом сравнения.

В javascript для сравнения можно использовать либо ==, либо ===. В случае тройного равенства это то, что известно как равенство без принуждения типа, другими словами, это строгое сравнение.

Равенство с типом принуждения

И наоборот, это означает, что использование двойного эквивалентного операнда - это равенство с типом принуждения.

Что это значит?

Проще говоря, это означает, что javascript будет использовать встроенные методы, чтобы преобразовать значение в примитивный тип, готовый для сравнения. В частности, эти методы .valueOf() и .toString().

Вот несколько примеров:

0 == false   // true, auto type coercion
0 === false  // false, because they are of a different type
1 == "1"     // true, auto type coercion
1 === "1"    // false, because they are of a different type

Ergo:

1 == [1] // true
1 === [1] // false, because they are of a different type