Почему в Javascript не равен [1,2,3]?

Сегодня я играл с массивами в Javascript и заметил этот маленький камень:

alert([1, 2, 3] == [1, 2, 3]); //alerts false

Мне кажется довольно странным, что массив не равен самому себе.

Но потом я заметил это, что было еще более странно:

alert([1, 2, 3] == "1,2,3");  //alerts true

?!?!?!? !!!?

Почему в мире [1, 2, 3] не == для себя, а есть == для строки?

Я понимаю, что == это не то же самое, что ===. Тем не менее, какое зло может вызвать г-н Javascript, такие странные вещи?

Ответ 1

Итак, сначала вам нужно понять, как javascript обрабатывает значения в вашей программе. Все ваши переменные, которые вы создаете, будут просто ссылками на место в памяти, где хранится этот объект. Поэтому, когда вы это делаете:

alert( [1,2,3] == [1,2,3] );

... он выполняет три вещи:

  • Поместите массив ([1,2,3]) в кучу
  • Поместите другой массив ([1,2,3]) в кучу (обратите внимание, что он будет иметь другую ячейку памяти)
  • Сравните две ссылки. Они указывают на разные объекты в разных местах в памяти, поэтому они считаются не равными.

Вы можете проверить правильное поведение, выполнив этот код:

var a = [1,2,3];
var b = a;
alert (a == b)   // Result is true. Both point to the same object.

Теперь для вашего вопроса о строке

Когда вы используете оператор ==, пытается преобразовать два операнда в один и тот же тип (злые поведении... я знаю...)

Когда он делает это, он решает преобразовать оба в строку до того, как он сравним (таким образом, результат действительно "1,2,3" === "1,2,3", который оценивается как true.

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

Ответ 2

В первой части вы создаете два разных объекта, поскольку массивы - это просто объекты, и поскольку вы создали два из них, они оба уникальны.

Ответ 3

== оператор

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

https://developer.mozilla.org/en/JavaScript/Reference/Operators/Comparison_Operators

То есть [1, 2, 3], преобразованный в строку, равен "1,2,3". Один объект массива не равен другому объекту массива.

Ответ 4

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

function arrayCompare(arr1, arr2) {
  if (arr1.length !== arr2.length) return false;
  for (var i = 0, len = arr1.length; i < len; i++) {
    if (arr1[i] !== arr2[i]) return false;
  }
  return true;
}

Просто помните, что это не рекурсивное сравнение, поэтому оно будет работать только с массивом примитивных значений.

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

[1,2,3].toString() === '1,2,3'

Ответ 5

Два объекта Array различаются и, следовательно, не равны при сравнении ==. Чтобы сравнить их, вам нужно будет зацикливать, проверка индекса в обоих идентична (и будет рекурсивной, если элементы тоже Array или Object s).

Во-вторых, поскольку Array неявно называл toString(), который возвратил '1,2,3' (попробуйте).

Это связано с тем, что по правилам a == (не строгого) сравнения в ECMAScript левый оператор был принужден к преобразованию типа String (==).

Ответ 6

Потому что == только коэрцирует, если ему нужно получить тот же тип (например, только в том случае, когда типы операндов отличаются). При выполнении

alert([1, 2, 3] == [1, 2, 3]); //alerts false

... принуждение не требуется; оба являются объектами. Это не тот же объект, поэтому он false. Люди думают о == как о "принудительном" операторе равенства, и это так, но ключ в том, что он только принуждает, если он должен.

Но делать

alert([1, 2, 3] == "1,2,3");  //alerts true

... включает в себя операнды разных типов: string и object. Так что принуждение сделано. В этом случае объект принуждается к строке, как будто с помощью String(obj), которая вызывает свое поведение по умолчанию toString, которое для массивов .join(). join по умолчанию используется "," как разделитель, поэтому итоговая строка соответствует "1,2,3". (Вы можете найти полную логику того, почему объект принуждается к строке в спецификации.)