¿Por qué el control de igualdad no funciona con arreglos

Empecé con:

"1:2".split(':') == ["1","2"]; // false 

Entonces intenté:

 [1,2] == [1,2]; // false 

y ultimamente:

 [] == []; // false 

Desde entonces he encontrado eso:

 "1:2".split(':').toString() == [1,2].toString(); // true 

Así que he resuelto mi problema inicial (tipo de) pero ¿por qué las matrices no pueden coincidir entre sí?

Las matrices de Javascript son objetos y no se puede usar simplemente el operador de igualdad == para comprender si el contenido de esos objetos es el mismo. El operador de igualdad solo probará si dos objetos son exactamente la misma instancia (por ejemplo, myObjVariable==myObjVariable , funciona también para null e undefined ).

Si necesita verificar si dos matrices son iguales, recomendaría atravesar ambas matrices y verificar que todos los elementos tengan el mismo valor (y que las dos matrices tengan la misma longitud).

En cuanto a la igualdad de objetos personalizados, construiría una función de equals específica y la agregaría al prototipo de su clase.

Teniendo en cuenta que al final convertiste ambas matrices a una String y probaste la igualdad de las cadenas resultantes, algún día podrías considerar usar una técnica similar pero más genérica que encontrarás descrita en más de unos pocos lugares:

 JSON.stringify(OBJ1) === JSON.stringify(OBJ2) 

Bueno, no lo hagas

Si bien esto podría funcionar si el orden de las propiedades siempre será el mismo para esas instancias de objetos, esto deja la puerta abierta para errores extremadamente desagradables que podrían ser difíciles de rastrear. Siempre favorezca un enfoque más explícito y simplemente escriba una función limpia y legible que verifique la igualdad de todos los campos requeridos.

El operador == para Objetos en Javascript solo comprueba si los objetos son la misma referencia de objeto real, no si son dos objetos separados que contienen el mismo contenido. No hay un operador incorporado para verificar si contienen los mismos contenidos. Tendría que escribir una función para hacer ese tipo de comparación usted mismo.

La conversión de cadenas es una forma de comparar dos matrices, siempre que los elementos de la matriz solo contengan valores primitivos (no otros objetos). Si los elementos de la matriz pueden contener otros elementos, entonces deberá asegurarse de que esos objetos también se hayan convertido en cadenas representativas.

Y, la conversión a una cadena no discerniría entre un elemento de matriz que contiene "4" versus uno que contiene 4 ya que ambos convierten a "4" en la representación de cadena.

Las matrices son objetos en JavaScript que pasan por referencia. Esto significa que cuando inicializo una matriz:

 var array = [1, 2, 3]; 

Creé una referencia a esa matriz en la memoria. Si digo entonces:

 var otherArray = [1 2, 3]; 

array y otherArray tienen dos direcciones separadas en la memoria, por lo que no se igualarán (aunque los valores sean iguales). Para probar el pase por referencia, puede jugar con las matrices haciendo:

 var copyArray = array; 

En este caso, copyArray hace referencia a la misma dirección en la memoria como una matriz, de modo que:

 copyArray === array; //will evaluate to true array.push(4); //copyArray will now have values [1, 2, 3, 4]; copyArray.push(5); //array will have values [1, 2, 3, 4, 5]; copyArray === array; //still true 

Para probar la igualdad de valores en una matriz u objeto, debe hacer una “comparación profunda”: para las matrices esto atravesará ambas matrices para comparar el índice y el valor para ver si ambas son iguales, para los objetos atravesará cada clave y hará seguro que el valor es el mismo Para obtener más información acerca de las comparaciones profundas, puede consultar la fuente anotada bajo underscore.js:

http://underscorejs.org/docs/underscore.html

En javascript, cada [] es una instancia de window.Array class. Entonces, básicamente, estás tratando de comparar dos objetos diferentes. Como las matrices pueden tener un no. y cualquier tipo de elementos, incluidos Objetos y Objetos Personalizados, y esas matrices anidadas pueden tener numerosas propiedades y matrices, y así sucesivamente.

Se vuelve ambiguo cuando se trata de comparar, nunca estarás seguro de qué quieres hacer con esos objetos y propiedades anidadas. Entonces, lo que estás tratando de lograr mediante la comparación se puede hacer de muchas otras maneras. Solo tienes que descubrir el camino correcto para tu caso.

Una forma es hacer su propia función de comprobación de Array :

¿Cómo comparar matrices en JavaScript? !

Otra forma es convertir la Array en una String con .join() y comparar las cadenas. Luego, .split() nuevamente en Array s con .split() .

La igualdad de los objetos le dirá si los dos objetos son el mismo .

 var a = []; var b = a; a === b; // True, a and b refer to the same object [] === []; // False, two separate objects 

Tendrás que recorrer las matrices para ver si tienen los mismos elementos.

Ver: ¿Cómo verificar si dos matrices son iguales a JavaScript?

Supongo que porque cuando se diseñó javascript, pensaron que la comparación de elemento inteligente era una característica raramente utilizada, por lo que nunca se puso en el lenguaje.

Esta característica es bastante rara en los idiomas populares; Java no lo admite, C # no lo admite, los tipos stl de C ++ no lo admiten.

La comparación inteligente de elementos es bastante costosa y complicada en comparación con la comparación de referencia.

En un mundo perfecto, todo se puede comparar por referencia, de modo que cada dos objetos que tengan el mismo estado tengan la misma referencia, lo que nos permite comprobar de forma económica la igualdad, simplemente comparando sus direcciones virtuales internas con una simple comparación numérica.

Desafortunadamente, no vivimos en un mundo perfecto, y lo anterior solo es posible para cadenas con un grupo de cadenas, junto con algunas otras opciones de caché relativamente costosas.

Algunos lenguajes como Prolog y Haskell permiten la comparación por valor; p.ej

 myProgram :- Object1 = [1, "something", true, [1,[[], []], true,[false]]], Object2 = [1, "something", false, [1,[[], []], true,[false]]], Object3 = [1, "something", true, [1,[[], []], true,[false]]], Object4 = [1, "something", false, [1,[[], []], true,[false]]], (Object1 = Object2 -> write("first test passed.") ; write("first test failed\n")), (Object1 = Object3 -> write("second test passed!\n") ; write("second test failed!\n")), (Object2 = Object4 -> write("third test passed!\n") ; write("third test failed!")). 

Puede implementar su propio comparador de profundidad en cualquier idioma usando un mapa desde el constructor hasta un comparador para ese constructor. Como JavaScript no tiene mapas de otra cosa que de una cadena a un objeto, y los clientes de JavaScript no tienen acceso al identificador único interno de los objetos, necesitamos usar una tabla con constructor, pares de comparadores, algo como a continuación.

 class MyList { constructor(a, b) { this.head_ = a; this.tail_ = b; } getHead() { return this.head_; } getTail() { return this.tail_; } setHead(x) { this.head_ = x; } setTail(x) { this.tail_ = x; } equals(other) { if (typeof other !== 'object') { console.log(other, 'EEP'); return false; } if (!(other instanceof MyList)) { console.log(other, 'EEP'); return false; } var h = this.head_; var ho = other.getHead(); var cmp1 = comparatorof(h); if (!cmp1(h, ho)) { return false; } var t = this.tail_; var to = other.getTail(); var cmp2 = comparatorof(t); if (!cmp2(t, to)) { return false; } return true; } } var object1 = { 0: "one", 1: "two", 2: ["one", "two", []], something: { 1: [false, true] } }; function strictComparator(a, b) { return a === b; } // given any object, tries finding a function for comparing // that object to objects of the same kind. Kind being // used loosely, since some objects like null resist being categorized, // so these objects need special alteration of the comparatorof itself. function comparatorof(x) { if (x === null || x === undefined) { return strictComparator; } x = Object(x); // promote primitives to objects var ctor = x.constructor; var c2ct = ctorToComparatorTable; var n = c2ct.length; for (var i = 0; i < n; ++i) { var record = c2ct[i]; var keyCtor = record[0]; if (keyCtor === ctor) { return record[1]; } } throw new TypeError('no comparator exists for ' + x); } var ctorToComparatorTable = [ [String, function(a, b) { return a == b; }], [Object, function(a, b) { for (var key in a) { var avalue = a[key]; var bvalue = b[key]; var cmp = comparatorof(avalue); if (!cmp(avalue, bvalue)) { return false; } } return true; }], [Number, function(a, b) { return a == b; }], [Boolean, function(a, b) { return a == b; }], [Array, function(as, bs) { if (typeof bs !== 'object') { return false; } var nAs = as.length; var nBs = bs.length; if (nAs !== nBs) { return false; } for (var i = 0; i < nAs; ++i) { var a = as[i]; var b = bs[i]; var cmp = comparatorof(a); if (!cmp(a, b)) { return false; } } return true; }], [MyList, function(a, b) { return a.equals(b); }] ]; // true console.log(comparatorof([])([new MyList(1, new MyList(2, 3))], [new MyList(1, new MyList(2, 3))])); // true console.log(comparatorof([])([{}, new MyList(1, new MyList(2, 3))], [{}, new MyList(1, new MyList(2, 3))])); // false console.log(comparatorof([])([{}, new MyList(1, new MyList(2, 3))], [{}, new MyList(1, new MyList(3, 3))])); // true console.log(comparatorof({})({ 1: 'one', one: '1', x: new MyList(1, {}) }, { 1: 'one', one: '1', x: new MyList(1, {}) })); // true console.log(comparatorof(2)( 3, 3 )); //true console.log(comparatorof(true)( true, true )); //false console.log(comparatorof([])( [1, 2, new MyList(1, 2)], [1, 2, new MyList(4, 9)] )); // true console.log(comparatorof([])( [1, 2, new MyList(1, 2), null], [1, 2, new MyList(1, 2), null] )); // false console.log(comparatorof(null)( null, undefined )); // true console.log(comparatorof(undefined)( undefined, undefined )); // true console.log(comparatorof(null)( null, null )); 

Un gran problema es que ES6 ya está lleno de características que son incompatibles con JScript y Jhor de Nashorn, así como con ActionScript, que el lenguaje también puede renombrarse como un lenguaje completamente nuevo cada pocos meses, considerando que eso es lo que obtienes cuando agregas un nuevo características a un idioma que rompa la compatibilidad con versiones anteriores que no pueden replicarse sin una capa adicional de evaluación.

Este problema se remonta a hace mucho tiempo, donde por un lado tienes un lenguaje mínimo como Lisp que es "más fácil" (aún no puedes sobrecargar al operador) para introducir características de "primera clase" sin romper la compatibilidad hacia atrás, y luego tienes lenguajes como Perl que no se puede extender con nuevas palabras clave de primera clase sin una capa de evaluación adicional. JavaScript eligió el segundo enfoque y generalmente elude las consecuencias al usar objetos auxiliares como Math, Object para introducir nuevas características, pero cada vez que quiere agregar "construcciones de primera clase" termina rompiendo la compatibilidad hacia atrás.

Como una prueba de concepto, en Lisp puedes sobrecargar el operador ==, mientras que en JavaScript no puedes, y en Perl puedes hacerlo a través de un mecanismo que reserva palabras clave.