2011-11-23 13 views
8

Me he encontrado con un código JavaScript que no puedo explicar. Por ejemplo:¿Cómo funciona la construcción ~ [] en JavaScript?

  • +[]===0
  • -[]===0
  • ~[]===-1
  • ~-~[]===-2
  • ~-~-~-~-~[]===-5
  • ~-~-~-~-~[]+~[]===-6
  • ~+~[]===0
  • ~+~+~[]===-1
  • ~+~+~+~[]===0

Puede explicar la lógica de estas expresiones?

+2

Creo que me gustaría voltear el escritorio si me encontré con un código como ese. –

+1

la respuesta es: '+ [NaN] == !!!! 0 && + [{}] + ~~ [[]] - []' – jAndy

+1

Si vi eso en cualquier código, le pediría al desarrollador original que reescriba eso. ¡Es una muy mala práctica! –

Respuesta

11

[] es un objeto matriz vacía, así que:

+ []: forzar matriz vacía ser entero positivo, también conocido como 0, que se === a 0
- []: forzar matriz vacía para ser entero negativo, también conocido como 0, que es === a 0
~ []: matriz NO vacía en modo bit, que evalúa a -1, que es === a -1
~ - ~ []: en modo bit NO de negado NOTted matriz vacía: ~-(-1) -> ~1 -> -2

etc ...

+1

debe ser: '~ 1 -> -2' en la última cadena – Denis

+0

Gracias, corrigió la respuesta. –

+0

-1 '+ []: forzar matriz vacía para ser entero positivo, aka 0, que es === a 0' no explica por qué sucede. Simplemente repite el resultado. Obviamente, si '+ [] === 0', entonces' + [] 'debe haberse convertido a' 0'. La pregunta pide explicar la lógica. – RightSaidFred

2

Cuando utiliza el operador + o - en cualquier cosa, llama al Number en él. Number([]) devuelve 0, por lo que obtiene sus primeras dos respuestas.

El operador ~ es NOT en modo bit. Básicamente, invierte todos los bits en un número, que cambia 0 a -1. Más sobre los operadores bit a bit here.

El resto son solo combinaciones de esos casos. Puedes combinar esas cosas para hacer el número que quieras.

+0

Lo tengo. Me perdí el lanzamiento de la parte '[]' a '0'. – Denis

0

Creo que corrígeme si me equivoco, pero agregar a una matriz (como agregar valor a una matriz en lugar de agregar un valor a una matriz) lo convierte en un número. El resto solo usa operadores básicos +, - (la tilde (~) es un NO bit a bit) para modificar el número y luego una ecuación.

So [] == array ([]); 
[] + 1 == number (0); 
+[]===0 (true) 
+0

en realidad lo lanzó a una cadena, no a un número. '[1] + 1 =" 11 "' so '+ [] = 0' porque es como hacer' + "" ' – pleasedontbelong

1

haré lo mejor:

[]===0 es, por supuesto falso porque [] no es exactamente igual a 0. Sin embargo, []==0 es cierto porque existe una conversión implícita.

+ y -[] funcionan porque el más o menos arroja [] a un número real.

~0 (el bitwise inverso de 0) es -1. Por lo tanto, ~[]===-1 funciona.

Los demás funcionan simplemente restando o agregando -1 un montón de veces.

2

En lugar de repetir el resultado que demostró en la pregunta, intentaré dar una descripción de por qué obtiene ese resultado.

Explicación

Tomando sólo el primer ejemplo (porque el resto va a hacer algo similar), podemos seguir la especificación para ver qué pasa.

De 11.4.6 Unary + Operator, podemos ver que se lleva a cabo una conversión de ToNumber.

Return ToNumber (GetValue (expr)).

De 9.3 ToNumber vemos que si se les da un objeto (como Array), una conversión ToPrimitive tiene lugar seguido de otro intento de ToNumber.

objeto

Aplicar los siguientes pasos:

  1. Vamos primValue ser ToPrimitive (argumento de entrada, Número de pista).
  2. Volver aNúmero (primValue).

De 9.1 To Primitive, si ToPrimitive Obtiene un objeto, podemos ver que su [[DefaultValue]] es inverosímil:

objeto

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

De 8.12.8 [[DefaultValue]] (hint), lo que finalmente suceda será que toString() serán llamados en la matriz, y regresaron. Esta cadena se envía al recursivo ToNumber como se describe arriba.

Entonces, ¿qué ocurre cuando la conversión ToNumber se realiza en una cadena? Bueno, se describe en 9.3.1 ToNumber Applied to the String Type, y es un poco largo. Más simple es simplemente hacer la conversión directa, y ver lo que sucede:

Number("");  // result is 0 on an empty string 
Number(" "); // result is 0 on a string with only whitespace 
Number("123"); // result is 123 on a numeric string 
Number(" 123 ");// result is 123 on a numeric string with leading & trailing spaces 
Number("abc"); // result is NaN (not a number) on non-numeric strings 

Entonces la pregunta es, ¿qué hacer cadena volvamos de nuestra matriz. De nuevo, esto es fácil de simplemente probar.

[].toString(); // result is "" (empty string) 

Como el resultado es una cadena vacía, y una conversión ToNumber de una cadena vacía es 0 como se muestra arriba, que significaría estamos comparando 0 === 0.

Sería lo mismo que si lo hicimos:

Number([].toString()) === 0; // true 

O a lo alcanzará un poco más:

var x = []; 
x = x.toString(); // "" 
x = Number(x); // 0 
x === 0; // true 

Más toString resultados.

para mostrar más toString conversiones de matrices, tenga en cuenta lo siguiente:

[1].toString();   // "1" 
[1,2,3].toString();  // "1,2,3" 
["a",1,"b",2].toString(); // "a,1,b,2" 

Así que para hacer una conversión ToNumber en las matrices anteriores, la primera sería darnos un número, y las dos últimas se traduciría en NaN.

Number([1]);   // 1 
Number([1,2,3]);  // NaN 
Number(["a",1,"b",2]); // NaN 

alguna prueba

Para proporcionar una prueba más de que esta conversión toString() ocurre antes de la conversión ToNumber, en realidad podemos modificar Array.prototype.toString para proporcionar un resultado diferente, y cualquier ToNumber conversiones utilizaremos dicha resultado modificado.

Array.prototype.toString = function() { 
    var n = 0; 
    for(var i = 0; i < this.length; i++) { 
     n += this[i]; 
    } 
    return n; 
}; 

Aquí he reemplazado el toString en Array.prototype con una función que resume la matriz. Obviamente, no quiere hacer esto, pero podemos mostrar cómo obtendremos un resultado diferente.

Number([1,2,3]); // 6 
+[1,2,3];   // 6 

Así que ahora se puede ver que la conversión ToNumber de nuestra matriz que anteriormente habrían dado lugar a NaN está dando lugar a la suma de los elementos de la matriz.

Cuestiones relacionadas