2009-11-12 24 views
160

Recientemente descubrí que 2 == [2] en JavaScript. Como resultado, esta peculiaridad tiene un par de consecuencias interesantes:¿Por qué 2 == [2] en JavaScript?

var a = [0, 1, 2, 3]; 
a[[2]] === a[2]; // this is true 

Del mismo modo, las siguientes obras:

var a = { "abc" : 1 }; 
a[["abc"]] === a["abc"]; // this is also true 

Incluso más extraño aún, esto funciona así:

[[[[[[[2]]]]]]] == 2; // this is true too! WTF? 

Estos comportamientos parecen consistentes en todos los navegadores.

¿Alguna idea de por qué esta es una función de idioma?

Estas son las consecuencias más demenciales de esta "característica":

[0] == false // true 
if ([0]) { /* executes */ } // [0] is both true and false! 

var a = [0]; 
a == a // true 
a == !a // also true, WTF? 

Estos ejemplos fueron encontrados por jimbojw http://jimbojw.com la fama, así como walkingeyerobot.

Respuesta

126

Puede buscar el algoritmo de comparación en la especificación ECMA (secciones relevantes de ECMA-262, 3ª edición para su problema: 11.9.3, 9.1, 8.6.2.6).

Si traduce los algoritmos abstractos involucradas volver a JS, lo que sucede cuando se evalúa 2 == [2] es básicamente el siguiente:

2 === Number([2].valueOf().toString()) 

donde valueOf() para matrices devuelve la matriz en sí y la cadena de representación de una matriz de elementos es la representación de cadena del elemento individual.

Esto también explica el tercer ejemplo como [[[[[[[2]]]]]]].toString() sigue siendo la cadena 2.

Como puede ver, hay un montón de magia detrás del escenario involucrada, por lo que generalmente solo uso el operador de igualdad estricta ===.

El primer y segundo ejemplo son más fáciles de seguir como nombres de propiedad son siempre cadenas, por lo

a[[2]] 

es equivalente a

a[[2].toString()] 

que es sólo

a["2"] 

Tenga en Tenga en cuenta que incluso las claves numéricas se tratan como nombres de propiedad (es decir, cadenas) antes de que ocurra cualquier magia de matriz.

6

Una matriz de un elemento se puede tratar como el elemento en sí.

Esto se debe a la mecanografía pato. Desde "2" == 2 == [2] y posiblemente más.

+8

2 === [2] no funciona. –

+0

Hmm así parece, mi mal. –

+4

porque no coinciden en tipo. en el primer ejemplo, el lado izquierdo se evalúa primero, y terminan emparejando en tipo. – Shawn

10

Es debido a la conversión de tipo implícita del operador ==.

[2] se convierte en Número es 2 en comparación con un número. Pruebe el operador único + en [2].

> +[2] 
2 
+0

Otros dicen que [2] se convierte en una cadena. '+" 2 "' también es el número 2. – dlamblin

+1

En realidad, no es tan fácil. [2] se convierte en cadena estaría más cerca, pero eche un vistazo a http://ecma-international.org/ecma-262/5.1/#sec-11.9.3 – neo

8

Para el caso ==, esta es la razón por Doug Crockford recomienda utilizar siempre ===. No realiza ninguna conversión de tipo implícita.

Para los ejemplos con ===, la conversión de tipo implícita se realiza antes de llamar al operador de igualdad.

+1

que usa === en su ejemplo. –

10
var a = [0, 1, 2, 3]; 
a[[2]] === a[2]; // this is true 

En el lado derecho de la ecuación, tenemos la a [2], que devuelve un tipo de número con el valor 2. A la izquierda, estamos primero creando una nueva matriz con un solo objeto de 2. Entonces estamos llamando a [[la matriz está aquí]]. No estoy seguro de si esto se evalúa como una cadena o un número. 2 o "2". Vamos a tomar el caso de cuerda primero. Creo que un ["2"] crearía una nueva variable y devolvería nulo. null! == 2. Asumamos que en realidad se está convirtiendo implícitamente en un número. a [2] devolvería 2. 2 y 2 coinciden en tipo (por lo que === funciona) y valor. Creo que está convirtiendo implícitamente la matriz en un número porque un [valor] espera una cadena o un número. Parece que el número tiene mayor prioridad.

En una nota lateral, me pregunto quién determina esa precedencia. ¿Es porque [2] tiene un número como primer elemento, por lo que se convierte en un número? ¿O es que al pasar una matriz a una [matriz] intenta convertir primero la matriz en un número, luego en una cadena? ¿Quién sabe?

var a = { "abc" : 1 }; 
a[["abc"]] === a["abc"]; 

En este ejemplo, está creando un objeto llamado a con un miembro llamado abc. El lado derecho de la ecuación es bastante simple; es equivalente a a.abc. Esto devuelve 1. Primero, el lado izquierdo crea una matriz literal de ["abc"]. A continuación, busca una variable en el objeto pasando la matriz recién creada. Como esto espera una cadena, convierte la matriz en una cadena.Esto ahora se evalúa como a ["abc"], que equivale a 1. 1 y 1 son del mismo tipo (por lo que === funciona) e igual valor.

[[[[[[[2]]]]]]] == 2; 

Esto es solo una conversión implícita. === no funcionaría en esta situación porque hay un desajuste de tipo.

+0

La respuesta a su pregunta sobre la precedencia: '==' aplica 'ToPrimitive()' a la matriz, que a su vez invoca su método 'toString()', entonces lo que realmente compara es el número '2' con la cadena' "2" '; la comparación entre una cadena y un número se hace convirtiendo la cadena – Christoph

3

Para añadir un pequeño detalle a las otras respuestas ... al comparar un Array a un Number, Javascript convertirá el Array con parseFloat(array). Puede probarlo usted mismo en la consola (por ejemplo, Firebug o Web Inspector) para ver a qué se convierten los diferentes valores Array.

parseFloat([2]); // 2 
parseFloat([2, 3]); // 2 
parseFloat(['', 2]); // NaN 

Para Array s, parseFloat realiza la operación en el primer miembro de la Array 's, y descarta el resto.

Editar: Per detalles de Christoph, puede ser que está utilizando la forma más larga internamente, pero los resultados son siempre idénticos a parseFloat, por lo que siempre puede utilizar parseFloat(array) como forma abreviada de saber con certeza cómo se va a convertir.

7
[0] == false // true 
if ([0]) { /* executes */ } // [0] is both true and false! 

Eso es interesante, no es que [0] es verdadero y falso, en realidad

[0] == true // false 

Es manera divertida de Javascript de transformación si) operador (.

+4

en realidad, es la forma divertida en que '==' funciona; si usa un modelo explícito real (es decir, 'Boolean ([0])' o '!! [0]'), encontrará que '[0]' evaluará a 'true' en contextos booleanos como debería: en JS, cualquier objeto se considera 'verdadero' – Christoph

1

Estás comparando 2 objetos en todos los casos ... No uses ==, si estás pensando en comparar, estás teniendo === y no ==. == a menudo puede dar efectos locos.Busque las partes buenas de la lengua :)

0

explicación de la sección deEDITAR de la pregunta: ¿

primera Ejemplo

[0] == false // true 
if ([0]) { /* executes */ } // [0] is both true and false! 

primer encasillado [0] en un valor simple como por la respuesta de Christoph anterior tenemos "0" ([0].valueOf().toString())

"0" == false 

Ahora, encasillada booleana (falso) a número y luego String ("0") a Número

Number("0") == Number(false) 
or 0 == 0 
so, [0] == false // true 

En cuanto a if declaración, si no hay una comparación explícita en el caso de condición en sí misma, la condición se evalúa para truey valores.

Sólo hay 6 valores de falsy: falso, nulo, indefinido, 0, NaN y cadena vacía "". Y cualquier cosa que no sea un valor falso es un valor verdadero.

Dado que [0] no es un valor falso, es un valor verdadero, la instrucción if se evalúa como verdadera & ejecuta la instrucción.


segundo Ejemplo

var a = [0]; 
a == a // true 
a == !a // also true, WTF? 

Una vez más la conversión de tipos de los valores de primitiva,

a = a 
or [0].valueOf().toString() == [0].valueOf().toString() 
or "0" == "0" // true; same type, same value 


a == !a 
or [0].valueOf().toString() == [0].valueOf().toString() 
or "0" == !"0" 
or "0" == false 
or Number("0") == Number(false) 
or 0 = 0 // true 
Cuestiones relacionadas