strong - ¿Cómo es 1==[1] en javascript?
undefined javascript error (3)
Si un objeto se compara con un número o cadena, JavaScript intenta devolver el valor predeterminado para el objeto. Los operadores intentan convertir el objeto en un valor primitivo, un valor de
String
oNumber
, utilizando los métodosvalueOf
ytoString
de los objetos. Si falla este intento de convertir el objeto, se genera un error de tiempo de ejecución. [ 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
Como el valor convertido es de tipo String
, al comparar un number
y una string
, la string
se convierte en un valor number
y luego se aplica una comparación estricta.
Esta pregunta ya tiene una respuesta aquí:
- ¿Por qué 2 == [2] en JavaScript? 9 respuestas
Recientemente me han hecho esta pregunta en una entrevista.
var a = 1;
var b = [1];
¿Qué a == b;
regreso.
Cuando lo compré en mi consola de navegador Chrome, obtuve esto.
var a = 1;
var b = [1];
a == b;
true
También he verificado
var a = 1;
var b =(1);
a == b;
true
Sé que b en una matriz de tamaño 1. ¿Eso significa que el tamaño de la matriz está asignado a b. Estoy realmente confundido. ¿Alguien puede explicarme la lógica?
Esto se debe al tipo de comparación que se está realizando.
En javascript, uno puede usar ==
o ===
para comparar. En el caso de un triple igual, esto es lo que se conoce como igualdad sin coerción de tipo , en otras palabras, es una comparación estricta.
Igualdad con coerción de tipo
Por el contrario, esto significa que usar el operando de doble igual es igualdad con la coerción de tipo.
¿Qué significa esto?
En pocas palabras, significa que javascript utilizará métodos incorporados para convertir el valor a un tipo primitivo, listo para la comparación. Específicamente, esos métodos son .valueOf()
y .toString()
.
Aquí hay unos ejemplos:
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
Es decir:
1 == [1] // true
1 === [1] // false, because they are of a different type
Realmente no entendí por Rayon cómo valueOf
y toString
entran en juego al convertir un objeto a un valor primitivo; así que profundicé en las especificaciones de ECMAScript 2015 .
Advertencia : respuesta larga.
Queremos verificar la expresión 1 == [1]
.
A partir de los 12.10 Operadores de igualdad vemos que, después de recuperar los valores de las expresiones, el último paso es
- Devuelve el resultado de la comparación abstracta de igualdad rval == lval
La comparación de igualdad abstracta se define en el capítulo 7.2.12 Comparación abstracta de igualdad .
7.2.12 Comparación abstracta de igualdad
La comparación x == y, donde xey son valores, produce verdadero o falso. Tal comparación se realiza de la siguiente manera:
- ReturnIfAbrupt (x).
- ReturnIfAbrupt (y).
- Si Tipo (x) es igual que Tipo (y), entonces
a. Devuelve el resultado de realizar la Comparación de igualdad estricta x === y.- Si x es nulo e y no está definido, devuelve true.
- Si x no está definido e y es nulo, devuelve verdadero.
- Si Type (x) es Number y Type (y) is String, devuelve el resultado de la comparación x == ToNumber (y).
- Si Type (x) es String y Type (y) es Number, devuelve el resultado de la comparación ToNumber (x) == y.
- Si Type (x) es Boolean, devuelve el resultado de la comparación ToNumber (x) == y.
- Si Type (y) es booleano, devuelva el resultado de la comparación x == ToNumber (y).
- Si Tipo (x) es Cadena, Número o Símbolo y Tipo (y) es Objeto, devuelva el resultado de la comparación x == APrimitivo (y).
- Si Type (x) es Object y Type (y) es String, Number o Symbol, devuelve el resultado de la comparación ToPrimitive (x) == y.
- Falso retorno.
La expresión 1 == [1]
cae bajo el caso 10 .
Entonces, básicamente, como se esperaba, la matriz [1]
se convierte en un valor de tipo primitivo.
ToPrimitive se define en 7.1.1 ToPrimitive (entrada [, PreferredType])
La operación abstracta ToPrimitive toma un argumento de entrada y un argumento opcional PreferredType. La operación abstracta ToPrimitive convierte su argumento de entrada en un tipo que no es un objeto.
No he incluido la cita completa ya que la única interesante, para este ejemplo , las partes son:
- El argumento PreferredType (en realidad, una var de sugerencia ) se convierte de "predeterminado" (dado que no se pasa) a "número".
-
OrdinaryToPrimitive
se llama con los mismos argumentos.
E ahora la parte interesante, OrdinaryToPrimitive hace lo siguiente:
- Assert: Type (O) is Object
- Assert: Type (hint) es String y su valor es "string" o "number".
- Si la sugerencia es "cadena", entonces
a. Deje methodNames ser «" toString "," valueOf "».- Más,
a. Deje methodNames ser «" valueOf "," toString "».- Para cada nombre en methodNames en el orden de la lista, haga
a. Deje que el método sea Get (O, name).
segundo. ReturnIfAbrupt (método).
do. Si IsCallable (método) es verdadero, entonces
... yo. Deje que el resultado sea Call (método, O).
... ii. ReturnIfAbrupt (resultado).
... iii. ** Si Tipo (resultado) no es un Objeto, devuelve el resultado. **- Lanzar una excepción TypeError
Entonces, para convertir [1]
a un valor primitivo, el tiempo de ejecución primero intenta llamar a valueOf
. Este método devuelve la matriz en sí, que es un objeto, por lo que mediante 5.c.iii se llama al método toString
siguiente.
Este método devuelve los elementos de la matriz como una lista separada por comas, por lo que solo devuelve la cadena "1"
.
Así que estamos reducidos al comparar 1 == "1"
que según las reglas de Abstract Equality Comparison , punto 6, significa convertir "1"
en el número 1
y que realizar la comparación trivial 1 = 1
.
El lector dudoso está invitado a comprobar cómo la Comparación de Igualdad Estricta está realmente definida en el estándar.
Puede jugar con estas conversiones para comprenderlas mejor, aquí un ejemplo de archivo HTML de juegos
<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>