(! [] + []) [+ []] ... Explique por que isso funciona

107
alert((![]+[])[+[]]+(![]+[])[+!+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]);

A saída desse código é: fail. Por quê?

A propósito (![]+[])[+!+[]] == 'false'[1], certo? Mas por quê ![]+[] == "false"e por quê +!+[] == 1?

cdxf
fonte
14
@Snoob, não confio em você. No final, é uma bomba de garfo.
Johannes Schaub - litb
3
É uma string literal, é claro;)
Yi Jiang
3
(![]+[])[+[]]é "f" (o primeiro caractere de "falso"), (![]+[])[+!+[]]é "a", etc.
Mauricio Scheffer
3
@Snoob: como você disse, você pode testar cada expressão em seu navegador. Experimente alert(![]+[])então alert(+!+[])e você verá.
Mauricio Scheffer
12
Inútil ou não, acho que é uma pergunta interessante e gostaria de ver uma explicação bem formulada. Muitos Code Golfs seriam fechados se a utilidade ou praticidade fossem consideradas. Exercícios e jogos são úteis em si mesmos para expandir a mente e o processo de pensamento.
John K

Respostas:

127

Como @Mauricio comentou (![]+[])[+[]]é "f" (o primeiro caractere de "false"), (![]+[])[+!+[]])é "a", etc ...

Como funciona?

Vamos examinar o primeiro caractere, 'f':

(![]+[])[+[]]; // 'f'

A primeira parte da expressão - entre parênteses - é composta por ![]+[], o primeiro operando do operador Addition é ![]e produzirá false, porque um objeto de matriz - como qualquer outra instância de Object - é verdadeiro e aplicando o lógico (!) NÃO unário operador, ele produz o valor false, por exemplo.

![]; // false, it was truthy
!{}; // false, it was truthy
!0;  // true, it was falsey
!NaN;  // true, it was falsey

Depois disso, temos o segundo operando da adição, um Array vazio,, []isso é feito apenas para converter o falsevalor para String, pois a representação em string de um array vazio é apenas uma string vazia, equivale a:

false+[]; // "false"
false+''; // "false"

A última parte, o par de colchetes após os parênteses, eles são os acessadores da propriedade e recebem uma expressão, que é formada pelo Operador Unário Plus aplicado novamente a um array vazio.

O que o Operador Unário Plus faz é a conversão de tipo Number, por exemplo:

typeof +"20"; // "number"

Mais uma vez, isso é aplicado a um Array vazio e, como eu disse antes, a representação em String de um Array é uma string vazia e, quando você converte uma string vazia em Número, ela é convertida em zero:

+[]; // 0, because
+[].toString(); // 0, because
+""; // 0

Portanto, podemos "decodificar" a expressão em algumas etapas:

(![]+[])[+[]];
(false+[])[+[]];
(false+'')[+[]];
(false+'')[0];
('false')[0];  // "f"

Observe que o acesso a caracteres usando a notação de colchetes em valores de String não fazia parte do ECMAScript 3rd. Especificação da edição, (é por isso que o charAtmétodo existia).

Porém este tipo de "propriedades de índice" que representam os caracteres de uma string foram padronizados no ECMAScript 5, e mesmo antes da padronização o recurso estava disponível em um bom número de navegadores (até mesmo no IE8 (modo padrão)).

CMS
fonte
46
Só espero que isso nunca seja uma pergunta de entrevista.
Inisheer
4
@JTA: Eu espero que isso é ! Eu teria passado :-D
Mauricio Scheffer
18
De onde vem o "i"?
Josh Stodola
5
@rlemon, não há inttipo de dados na linguagem, na verdade todos os números são no formato de dupla precisão de 64 bits (valores IEEE 754), embora alguns operadores trabalhem internamente com valores inteiros (como os operadores bit a bit), o resultado é sempre um duplo . O 'i'vem neste exemplo de undefined, mas poderia vir, Infinitypor exemplo: (+!+[]/+[+[]]+[])[!+[]+!+[]+!+[]]=> (1/0+'')[3]=> (Infinity+'')[3]=>'i'
CMS
5
@JoshStodola Bem, ~ 3 meses depois, mais um esclarecimento. O "i" neste caso vem de "indefinido", sim, mas há outro truque envolvido aqui. O código concatena "false" para "undefined" para formar "falseundefined"(construído usando [![]]+[][[]]:) em que o índice de "i" é 10. +!+[]+[+[]]"10". Isso é usado para extrair o "i" (índices de string podem ser usados ​​em javascript se eles puderem ser convertidos em inteiros aparentemente). A construção final que o produz é:([![]]+[][[]])[+!+[]+[+[]]]
entropia