Esto es válido y devuelve la cadena "10"
en JavaScript ( más ejemplos aquí ):
console.log(++[[]][+[]]+[+[]])
¿Por qué? ¿Que está sucediendo aquí?
javascript
syntax
SapuSeven
fuente
fuente
+[]
arroja una matriz vacía para0
... luego desperdiciar una tarde ...;)Respuestas:
Si lo dividimos, el desorden es igual a:
En JavaScript, es cierto eso
+[] === 0
.+
convierte algo en un número, y en este caso se reducirá a+""
o0
(consulte los detalles de la especificación a continuación).Por lo tanto, podemos simplificarlo (
++
tiene precedencia sobre+
):Porque
[[]][0]
significa: obtener el primer elemento de[[]]
, es cierto que:[[]][0]
devuelve la matriz interna ([]
). Debido a las referencias, es incorrecto decirlo[[]][0] === []
, pero llamemos a la matriz internaA
para evitar la notación incorrecta.++
antes de su operando significa "incrementar en uno y devolver el resultado incrementado". Entonces++[[]][0]
es equivalente aNumber(A) + 1
(o+A + 1
).Nuevamente, podemos simplificar el desorden en algo más legible. Vamos a sustituir de
[]
nuevo porA
:Antes de
+[]
poder forzar la matriz en el número0
, primero debe ser forzada a una cadena, que es""
, nuevamente. Finalmente,1
se agrega, lo que resulta en1
.(+[] + 1) === (+"" + 1)
(+"" + 1) === (0 + 1)
(0 + 1) === 1
Simplifiquemos aún más:
Además, esto es cierto en JavaScript:
[0] == "0"
porque une una matriz con un elemento. Unirse concatenará los elementos separados por,
. Con un elemento, puede deducir que esta lógica dará como resultado el primer elemento en sí.En este caso,
+
ve dos operandos: un número y una matriz. Ahora está tratando de obligar a los dos a ser del mismo tipo. Primero, la matriz se convierte en la cadena"0"
, luego, el número se convierte en una cadena ("1"
). Número+
Cadena===
Cadena .Detalles de especificación para
+[]
:Esto es todo un laberinto, pero para hacerlo
+[]
, primero se está convirtiendo en una cadena porque eso es lo que+
dice:ToNumber()
dice:ToPrimitive()
dice:[[DefaultValue]]
dice:El
.toString
de una matriz dice:Entonces
+[]
se reduce a+""
, porque[].join() === ""
.Nuevamente, el
+
se define como:ToNumber
se define""
como:Así
+"" === 0
y así+[] === 0
.fuente
true
si tanto el valor como el tipo son iguales.0 == ""
devuelvetrue
(lo mismo después de la conversión de tipos), pero0 === ""
esfalse
(no los mismos tipos).1 + [0]
, no"1" + [0]
, porque el++
operador prefijo ( ) siempre devuelve un número. Ver bclary.com/2004/11/07/#a-11.4.4++[[]][0]
vuelve de hecho1
, pero++[]
arroja un error. Esto es notable porque parece++[[]][0]
que se reduce a++[]
. ¿Quizás tienes alguna idea de por qué++[]
arroja un error mientras++[[]][0]
que no?PutValue
llamada (en la terminología de ES3, 8.7.2) en la operación de prefijo.PutValue
requiere una referencia mientras que[]
como una expresión por sí sola no produce una referencia. Una expresión que contiene una referencia variable (digamos que habíamos definido previamente yvar a = []
luego++a
funciona) o el acceso a la propiedad de un objeto (como[[]][0]
) produce una Referencia. En términos más simples, el operador de prefijo no solo produce un valor, sino que también necesita un lugar para poner ese valor.var a = []; ++a
,a
es 1. Después de ejecutar++[[]][0]
, la matriz creada por la[[]]
expresión ahora contiene solo el número 1 en el índice 0.++
requiere una Referencia para hacer esto.Entonces tenemos una concatenación de cuerdas
fuente
===
que=>
?Lo siguiente está adaptado de una publicación de blog respondiendo esta pregunta que publiqué mientras esta pregunta aún estaba cerrada. Los enlaces son a (una copia HTML de) la especificación ECMAScript 3, que sigue siendo la línea de base para JavaScript en los navegadores web más utilizados en la actualidad.
Primero, un comentario: este tipo de expresión nunca va a aparecer en ningún entorno de producción (sano) y solo es útil como ejercicio de cuán bien el lector conoce los bordes sucios de JavaScript. El principio general de que los operadores de JavaScript convierten implícitamente entre tipos es útil, como lo son algunas de las conversiones comunes, pero gran parte de los detalles en este caso no lo son.
La expresión
++[[]][+[]]+[+[]]
puede parecer inicialmente bastante imponente y oscura, pero en realidad es relativamente fácil dividirla en expresiones separadas. A continuación, simplemente agregué paréntesis para mayor claridad; Puedo asegurarle que no cambian nada, pero si desea verificar eso, no dude en leer sobre el operador de agrupación . Entonces, la expresión se puede escribir más claramente comoDesglosando esto, podemos simplificar observando que
+[]
evalúa a0
. Para satisfacerse por qué esto es cierto, consulte el operador unario + y siga el rastro ligeramente tortuoso que termina con ToPrimitive convirtiendo la matriz vacía en una cadena vacía, que finalmente es convertida0
por ToNumber . Ahora podemos sustituir0
cada instancia de+[]
:Más simple ya. En cuanto a
++[[]][0]
, esa es una combinación del operador de incremento de prefijo (++
), un literal de matriz que define una matriz con un solo elemento que es en sí misma una matriz vacía ([[]]
) y un descriptor de acceso de propiedad ([0]
) llamado en la matriz definida por el literal de matriz.Entonces, podemos simplificar
[[]][0]
a justos[]
y tenemos++[]
, ¿verdad? De hecho, este no es el caso porque la evaluación++[]
arroja un error, que inicialmente puede parecer confuso. Sin embargo, un poco de reflexión sobre la naturaleza de++
esto lo deja claro: se usa para incrementar una variable (por ejemplo++i
) o una propiedad de objeto (por ejemplo++obj.count
). No solo evalúa un valor, sino que también almacena ese valor en algún lugar. En el caso de++[]
, no tiene dónde colocar el nuevo valor (sea lo que sea) porque no hay referencia a una propiedad o variable de objeto para actualizar. En términos específicos , esto está cubierto por la operación interna PutValue , que es llamada por el operador de incremento de prefijo.Entonces, ¿qué hace
++[[]][0]
? Bueno, por una lógica similar+[]
, la matriz interna se convierte0
y este valor se incrementa1
para darnos un valor final de1
. El valor de la propiedad0
en la matriz externa se actualiza1
y toda la expresión se evalúa como1
.Esto nos deja con
... que es un uso simple del operador de suma . Ambos operandos se convierten primero en primitivas y si cualquiera de los valores primitivos es una cadena, se realiza la concatenación de cadenas, de lo contrario se realiza la suma numérica.
[0]
convierte a"0"
, por lo que se utiliza la concatenación de cadenas, produciendo"10"
.Como último comentario, algo que puede no ser inmediatamente aparente es que anular cualquiera de los métodos
toString()
o cambiará el resultado de la expresión, porque ambos se verifican y se usan si están presentes al convertir un objeto en un valor primitivo. Por ejemplo, lo siguientevalueOf()
Array.prototype
... produce
"NaNfoo"
. Por qué sucede esto se deja como ejercicio para el lector ...fuente
Hagámoslo simple:
fuente
Este se evalúa igual pero un poco más pequeño
entonces se evalúa a
Así que ahora lo tienes, prueba este:
fuente
"10"
+ [] se evalúa a 0 [...] y luego lo suma (+ operación) con cualquier cosa convierte el contenido de la matriz a su representación de cadena que consiste en elementos unidos con una coma.
Cualquier otra cosa como tomar el índice de la matriz (tiene mayor prioridad que la operación +) es ordinal y no es nada interesante.
fuente
Quizás las formas más cortas posibles de evaluar una expresión en "10" sin dígitos son:
+!+[] + [+[]]
// "10"-~[] + [+[]]
// "10"// ========== Explicación ========== \\
+!+[]
:+[]
Convierte a 0.!0
convierte atrue
.+true
se convierte en 1.-~[]
=-(-1)
que es 1[+[]]
:+[]
Convierte a 0.[0]
es una matriz con un solo elemento 0.Entonces JS evalúa la expresión
1 + [0]
, por lo tantoNumber + Array
. Entonces, la especificación ECMA funciona: el+
operador convierte ambos operandos en una cadena llamando a lastoString()/valueOf()
funciones desde elObject
prototipo base . Funciona como una función aditiva si ambos operandos de una expresión son solo números. El truco es que las matrices convierten fácilmente sus elementos en una representación de cadena concatenada.Algunos ejemplos:
Hay una buena excepción de que dos
Objects
resultados adicionales sumanNaN
:fuente
+ '' o + [] evalúa 0.
fuente
[]
es no equivalente a""
. Primero se extrae el elemento, luego se convierte por++
.Paso a paso,
+
cambie el valor a un número y si agrega a una matriz vacía+[]
... como está vacía y es igual a0
, seráA partir de ahí, ahora mira tu código, es
++[[]][+[]]+[+[]]
...Y hay más entre ellos
++[[]][+[]]
+[+[]]
Entonces estos
[+[]]
regresarán[0]
ya que tienen una matriz vacía que se convierte0
dentro de la otra matriz ...Entonces, como se imagina, el primer valor es una matriz bidimensional con una matriz dentro ... por
[[]][+[]]
lo que será igual a la[[]][0]
que volverá[]
...Y al final
++
convertirlo y aumentarlo a1
...Para que puedas imaginar,
1
+"0"
será"10"
...fuente