una recorrer primer leer dividir cortar caracteres caracter cadena buscar javascript syntax

javascript - recorrer - ¿Por qué++[[]][+[]]+[+[]] devuelve la cadena "10"?



primer caracter de un string javascript (8)

  1. Unario más una cadena dada se convierte en número
  2. Incremento de operador dado a la cadena que se convierte e incrementa en 1
  3. [] == ''''. Cuerda vacía
  4. + '''' o + [] evalúa 0.

    ++[[]][+[]]+[+[]] = 10 ++[''''][0] + [0] : First part is gives zeroth element of the array which is empty string 1+0 10

Esto es válido y devuelve la cadena "10" en JavaScript ( más ejemplos aquí ):

console.log(++[[]][+[]]+[+[]])

¿Por qué? ¿Que está sucediendo aquí?


Éste se evalúa al mismo pero un poco más pequeño.

+!![]+''''+(+[])

  • [] - es una matriz que se convierte a 0 cuando la suma o la resta, por lo tanto, + [] = 0
  • ! [] - evalúa a falso, entonces por lo tanto !! [] evalúa a verdadero
  • + !! [] - convierte el verdadero en un valor numérico que se evalúa en verdadero, por lo que en este caso 1
  • + '''': agrega una cadena vacía a la expresión que causa que el número se convierta en cadena
  • + [] - evalúa a 0

así se evalúa a

+(true) + '''' + (0) 1 + '''' + 0 "10"

Así que ahora tienes eso, prueba este:

_=$=+[],++_+''''+$


+ [] evalúa a 0 y luego [...] sumándolo (+ operación) con cualquier cosa convierte el contenido del arreglo a su representación de cadena que consiste en elementos unidos con una coma.

Cualquier otra cosa como tomar índice de matriz (tiene mayor prioridad que + operación) es ordinal y no es nada interesante.


Hagámoslo simple:

++[[]][+[]]+[+[]] = "10" var a = [[]][+[]]; var b = [+[]]; // so a == [] and b == [0] ++a; // then a == 1 and b is still that array [0] // when you sum the var a and an array, it will sum b as a string just like that: 1 + "0" = "10"


Lo siguiente está adaptado de una publicación de blog que responde a esta pregunta que publiqué mientras esta pregunta aún estaba cerrada. Los enlaces son a (una copia HTML de) la especificación ECMAScript 3, aún la línea de base para JavaScript en los navegadores web más utilizados en la actualidad.

En primer lugar, un comentario: este tipo de expresión nunca se mostrará en ningún entorno de producción (sano) y solo sirve como ejercicio, en la medida en que el lector conoce los bordes sucios de JavaScript. El principio general de que los operadores de JavaScript se 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 ++[[]][+[]]+[+[]] inicialmente puede parecer bastante imponente y oscura, pero en realidad es relativamente fácil de dividir en expresiones separadas. A continuación simplemente he agregado paréntesis para mayor claridad; Puedo asegurarte que no cambian nada, pero si quieres verificar eso, siéntete libre de leer sobre el operador de agrupación . Así, la expresión se puede escribir más claramente como

( ++[[]][+[]] ) + ( [+[]] )

Desglosando esto, podemos simplificar observando que +[] evalúa a 0 . Para satisfacer por qué esto es cierto, revise 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 se convierte en 0 por ToNumber . Ahora podemos sustituir 0 por cada instancia de +[] :

( ++[[]][0] ) + [0]

Más simple ya. En cuanto a ++[[]][0] , es una combinación del bclary.com/2004/11/07/#a-11.4.4 ( ++ ), un literal de matriz que define una matriz con un solo elemento que es en sí misma una matriz vacía ( [[]] ) y un elemento de acceso a la propiedad ( [0] ) llamado en la matriz definida por la matriz literal.

Entonces, podemos simplificar [[]][0] a solo [] y tenemos ++[] , ¿verdad? De hecho, este no es el caso porque la evaluación de ++[] produce un error, que inicialmente puede parecer confuso. Sin embargo, un pequeño pensamiento sobre la naturaleza de ++ deja claro: se utiliza para incrementar una variable (por ejemplo, ++i ) o una propiedad de objeto (por ejemplo, ++obj.count ). No solo evalúa 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 cual sea) porque no hay ninguna referencia a una propiedad o variable de objeto para actualizar. En términos PutValue , esto está cubierto por la operación interna PutValue , que es llamada por el operador de incremento de prefijo.

Entonces, ¿qué hace ++[[]][0] ? Bueno, con una lógica similar a +[] , la matriz interna se convierte a 0 y este valor se incrementa en 1 para darnos un valor final de 1 . El valor de la propiedad 0 en la matriz externa se actualiza a 1 y la expresión completa se evalúa a 1 .

Esto nos deja con

1 + [0]

... que es un uso simple del operador de suma . Ambos operandos se ToPrimitive primero ToPrimitive y si cualquiera de los valores primitivos es una cadena, se realiza la concatenación de cadenas, de lo contrario se realiza una suma numérica. [0] convierte a "0" , por lo que se utiliza la concatenación de cadenas, produciendo "10" .

Dejando de lado, algo que puede no ser inmediatamente evidente es que anular uno de los métodos toString() o valueOf() de Array.prototype 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, los siguientes

Array.prototype.toString = function() { return "foo"; }; ++[[]][+[]]+[+[]]

... produce "NaNfoo" . Por qué sucede esto se deja como un ejercicio para el lector ...


Quizás las maneras más cortas posibles de evaluar una expresión en "10" sin dígitos son:

+!+[] + [+[]] // "10"

-~[] + [+[]] // "10"

// ========== Explicación ========== //

+!+[] : +[] convierte en 0. !0 convierte en true . +true convierte a 1. -~[] = -(-1) que es 1

[+[]] : +[] Convierte a 0. [0] es una matriz con un solo elemento 0.

Luego JS evalúa el 1 + [0] , por lo tanto la expresión Number + Array . Luego, la especificación ECMA funciona: el operador + convierte ambos operandos en una cadena llamando a las funciones toString()/valueOf() del prototipo de Object 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:

1 + {} // "1[object Object]" 1 + [] // "1" 1 + new Date() // "1Wed Jun 19 2013 12:13:25 GMT+0400 (Caucasus Standard Time)"

Hay una buena excepción de que la adición de dos Objects da como resultado NaN :

[] + [] // "" [1] + [2] // "12" {} + {} // NaN {a:1} + {b:2} // NaN [1, {}] + [2, {}] // "1,[object Object]2,[object Object]"


Si lo dividimos, el lío es igual a:

++[[]][+[]] + [+[]]

En JavaScript, es cierto que +[] === 0 . + convierte algo en un número, y en este caso se reducirá a +"" o 0 (consulte los detalles de la especificación a continuación).

Por lo tanto, podemos simplificarlo ( ++ tiene precedencia sobre + ):

++[[]][0] + [0]

Debido a que [[]][0] significa: obtener el primer elemento de [[]] , es cierto que:

  • [[]][0] devuelve la matriz interna ( [] ). Debido a las referencias, es incorrecto decir [[]][0] === [] , pero llamemos a la matriz interna A para evitar la notación incorrecta.
  • ++[[]][0] == A + 1 , ya que ++ significa "incremento en uno".
  • ++[[]][0] === +(A + 1) ; en otras palabras, siempre será un número ( +1 no necesariamente devuelve un número, mientras que ++ siempre lo hace, gracias a Tim Down por señalarlo).

Nuevamente, podemos simplificar el desorden en algo más legible. Vamos a sustituir [] nuevo por A :

+([] + 1) + [0]

En JavaScript, esto también es cierto: [] + 1 === "1" , porque [] == "" (unirse a una matriz vacía), por lo tanto:

  • +([] + 1) === +("" + 1) , y
  • +("" + 1) === +("1") , y
  • +("1") === 1

Simplifiquémoslo aún más:

1 + [0]

Además, esto es cierto en JavaScript: [0] == "0" , porque está uniendo una matriz con un elemento. La unión concatenará los elementos separados por,. Con un elemento, puede deducir que esta lógica dará como resultado el primer elemento en sí.

Entonces, al final obtenemos (número + cadena = cadena):

1 + "0" === "10" // Yay!

Detalles de la especificación para +[] :

Esto es bastante un laberinto, pero para hacer +[] , primero se está convirtiendo en una cadena porque eso es lo que + dice:

11.4.6 Operador Unario +

El operador unario + convierte su operando al tipo de Número.

La producción de UnaryExpression: + UnaryExpression se evalúa de la siguiente manera:

  1. Sea expr el resultado de evaluar UnaryExpression.

  2. Vuelva a número (GetValue (expr)).

ToNumber() dice:

Objeto

Aplique los siguientes pasos:

  1. Deje que primValue sea ToPrimitive (argumento de entrada, pista String).

  2. Devuelve ToString (primValue).

ToPrimitive() dice:

Objeto

Devuelve un valor predeterminado para el objeto. El valor predeterminado de un objeto se recupera llamando al [[DefaultValue]] método interno del objeto, pasando la sugerencia opcional PreferredType. El comportamiento del [[DefaultValue]] método interno está definido por esta especificación para todos los objetos ECMAScript nativos en 8.12.8.

[[DefaultValue]] dice:

8.12.8 [[DefaultValue]] (pista)

Cuando se llama al [[DefaultValue]] método interno de O con hint String, se toman los siguientes pasos:

  1. Deje que toString sea el resultado de llamar al método interno [[Get]] del objeto O con el argumento "toString".

  2. Si IsCallable (toString) es verdadero entonces,

a. Deje que str sea el resultado de llamar al método interno de [[Call]] de toString, con O como el valor de este y una lista de argumentos vacía.

segundo. Si str es un valor primitivo, devuelva str.

El .toString de una matriz dice:

15.4.4.2 Array.prototype.toString ()

Cuando se llama al método toString, se toman los siguientes pasos:

  1. Deje que array sea el resultado de llamar a ToObject en este valor.

  2. Deje que func sea el resultado de llamar al [[Get]] método interno de matriz con el argumento "join".

  3. Si IsCallable (func) es falso, entonces permita que func sea el método estándar incorporado Object.prototype.toString (15.2.4.2).

  4. Devuelva el resultado de llamar al [[Call]] método interno de func que proporciona una matriz como este valor y una lista de argumentos vacía.

Entonces +[] se reduce a +"" , porque [].join() === "" .

De nuevo, el + se define como:

11.4.6 Operador Unario +

El operador unario + convierte su operando al tipo de Número.

La producción de UnaryExpression: + UnaryExpression se evalúa de la siguiente manera:

  1. Sea expr el resultado de evaluar UnaryExpression.

  2. Vuelva a número (GetValue (expr)).

ToNumber se define para "" como:

El MV de StringNumericLiteral ::: [empty] es 0.

Entonces +"" === 0 , y por lo tanto +[] === 0 .


++[[]][+[]] => 1 // [+[]] = [0], ++0 = 1 [+[]] => [0]

Entonces tenemos una concatenación de cuerdas.

1+[0].toString() = 10