Почему в 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"
. (Вы можете найти полную логику того, почему объект принуждается к строке в спецификации.)