Isso é válido e retorna a string "10"
em JavaScript ( mais exemplos aqui ):
console.log(++[[]][+[]]+[+[]])
Por quê? O que esta acontecendo aqui?
javascript
syntax
SapuSeven
fonte
fonte
+[]
lança uma matriz vazia para0
... depois desperdice uma tarde ...;)Respostas:
Se dividirmos, a bagunça é igual a:
Em JavaScript, é verdade isso
+[] === 0
.+
converte algo em um número e, nesse caso, será reduzido a+""
ou0
(consulte os detalhes das especificações abaixo).Portanto, podemos simplificá-lo (
++
tem precedência sobre+
):Porque
[[]][0]
significa: obter o primeiro elemento[[]]
, é verdade que:[[]][0]
retorna a matriz interna ([]
). Devido às referências, é errado dizer[[]][0] === []
, mas vamos chamar a matriz internaA
para evitar a notação errada.++
antes de seu operando significa "incrementar por um e retornar o resultado incrementado". Então++[[]][0]
é equivalente aNumber(A) + 1
(ou+A + 1
).Novamente, podemos simplificar a bagunça em algo mais legível. Vamos substituir
[]
novamente porA
:Antes de
+[]
poder coagir a matriz no número0
, ela precisa ser coagida em uma cadeia primeiro, ou seja""
, novamente. Por fim,1
é adicionado, o que resulta em1
.(+[] + 1) === (+"" + 1)
(+"" + 1) === (0 + 1)
(0 + 1) === 1
Vamos simplificar ainda mais:
Além disso, isso é verdade no JavaScript:
[0] == "0"
porque está juntando uma matriz com um elemento. A junção concatenará os elementos separados por,
. Com um elemento, você pode deduzir que essa lógica resultará no próprio elemento.Nesse caso,
+
vê dois operandos: um número e uma matriz. Agora, ele está tentando coagir os dois no mesmo tipo. Primeiro, o array é coagido na string"0"
; em seguida, o número é coagido em uma string ("1"
). Number+
String===
String .Detalhes da especificação para
+[]
:Este é um labirinto, mas, para fazer
+[]
, primeiro ele está sendo convertido em uma string, porque é o que+
diz:ToNumber()
diz:ToPrimitive()
diz:[[DefaultValue]]
diz:O
.toString
de uma matriz diz:Então tudo
+[]
se resume a+""
, porque[].join() === ""
.Novamente, o
+
é definido como:ToNumber
é definido""
como:Então
+"" === 0
e assim+[] === 0
.fonte
true
se o valor e o tipo forem iguais.0 == ""
retornatrue
(o mesmo após a conversão de tipo), mas0 === ""
éfalse
(não é o mesmo tipo).1 + [0]
, não"1" + [0]
, porque o++
operador prefix ( ) sempre retorna um número. Veja bclary.com/2004/11/07/#a-11.4.4++[[]][0]
retorna de fato1
, mas++[]
gera um erro. Isso é notável porque parece que++[[]][0]
tudo se resume a++[]
. Você talvez tenha alguma idéia de por que++[]
lança um erro++[[]][0]
e não o faz?PutValue
chamada (na terminologia ES3, 8.7.2) na operação de prefixo.PutValue
requer uma referência, enquanto[]
uma expressão por si só não produz uma referência. Uma expressão que contém uma referência variável (dizer que tinha previamente definidovar a = []
, em seguida,++a
trabalha) ou acesso a propriedade de um objeto (como[[]][0]
) produz uma referência. Em termos mais simples, o operador de prefixo não apenas produz um valor, mas também precisa de um lugar para colocar esse valor.var a = []; ++a
,a
é 1. Após a execução++[[]][0]
, a matriz criada pela[[]]
expressão agora contém apenas o número 1 no índice 0.++
requer uma Referência para fazer isso.Então nós temos uma concatenação de strings
fonte
===
do que=>
?O seguinte é adaptado de uma postagem de blog que respondeu a essa pergunta que eu postei enquanto ela ainda estava fechada. Os links são para (uma cópia em HTML) da especificação do ECMAScript 3, ainda a linha de base do JavaScript nos navegadores da web mais usados atualmente.
Primeiro, um comentário: esse tipo de expressão nunca será exibido em qualquer ambiente de produção (sadio) e é de alguma utilidade como um exercício de quão bem o leitor conhece as arestas sujas do JavaScript. O princípio geral de que os operadores JavaScript convertem implicitamente entre tipos é útil, assim como algumas conversões comuns, mas muitos dos detalhes nesse caso não são.
A expressão
++[[]][+[]]+[+[]]
pode inicialmente parecer bastante imponente e obscura, mas na verdade é relativamente fácil dividir-se em expressões separadas. Abaixo, simplesmente adicionei parênteses para maior clareza; Posso garantir que eles não mudam nada, mas se você quiser verificar isso, fique à vontade para ler sobre o operador de agrupamento . Portanto, a expressão pode ser escrita mais claramente comoPor fim, podemos simplificar observando o que é
+[]
avaliado como0
. Para saber por que isso é verdade, confira o operador unary + e siga a trilha um pouco tortuosa que acaba com o ToPrimitive convertendo a matriz vazia em uma string vazia, que é finalmente convertida0
pelo ToNumber . Agora podemos substituir0
cada instância de+[]
:Já é mais simples. Quanto a
++[[]][0]
isso, é uma combinação do operador de incremento de prefixo (++
), um literal de matriz que define uma matriz com um único elemento que é uma matriz vazia ([[]]
) e um acessador de propriedade ([0]
) chamado na matriz definida pelo literal da matriz.Então, podemos simplificar
[[]][0]
para justamente[]
e temos++[]
, certo? De fato, esse não é o caso, porque a avaliação++[]
gera um erro, que pode inicialmente parecer confuso. No entanto, um pouco de reflexão sobre a natureza de++
deixa isso claro: é usado para incrementar uma variável (por exemplo++i
) ou uma propriedade de objeto (por exemplo++obj.count
). Além de avaliar um valor, ele também armazena esse valor em algum lugar. No caso de++[]
, ele não tem onde colocar o novo valor (seja ele qual for), porque não há referência a uma propriedade ou variável de objeto a ser atualizada. Em termos de especificação, isso é coberto pela operação PutValue interna , chamada pelo operador de incremento de prefixo.Então, o que
++[[]][0]
faz? Bem, por uma lógica semelhante à+[]
, a matriz interna é convertida em0
e esse valor é incrementado por1
para nos dar um valor final de1
. O valor da propriedade0
na matriz externa é atualizado1
e a expressão inteira é avaliada em1
.Isso nos deixa com
... que é um uso simples do operador de adição . Ambos os operandos são primeiro convertidos em primitivos e se um dos valores primitivos for uma sequência, a concatenação da sequência será executada, caso contrário, a adição numérica será realizada.
[0]
converte em"0"
, então a concatenação de string é usada, produzindo"10"
.Como um aspecto final, algo que pode não ser imediatamente aparente é que a substituição de um dos métodos
toString()
ou alterará o resultado da expressão, porque ambos são verificados e usados se presentes ao converter um objeto em um valor primitivo. Por exemplo, o seguintevalueOf()
Array.prototype
... produz
"NaNfoo"
. Por que isso acontece é deixado como um exercício para o leitor ...fonte
Vamos simplificar:
fonte
Este avalia para o mesmo, mas um pouco menor
então é avaliado como
Então agora você conseguiu, tente este:
fonte
"10"
+ [] é avaliado como 0 e, em seguida, somado (+ operação) com qualquer coisa converte o conteúdo da matriz em sua representação de string, consistindo em elementos unidos por vírgula.
Qualquer outra coisa como pegar o índice da matriz (tem prioridade maior que + operação) é ordinal e não é nada interessante.
fonte
Talvez as formas mais curtas possíveis de avaliar uma expressão em "10" sem dígitos sejam:
+!+[] + [+[]]
// "10"-~[] + [+[]]
// "10"// ========== Explicação ========== \\
+!+[]
:+[]
Converte em 0.!0
converte emtrue
.+true
converte para 1.-~[]
=-(-1)
que é 1[+[]]
:+[]
Converte em 0.[0]
é uma matriz com um único elemento 0.Então JS avalia a expressão
1 + [0]
, portantoNumber + Array
. Em seguida, a especificação ECMA funciona: o+
operador converte os dois operandos em uma string chamando astoString()/valueOf()
funções doObject
protótipo de base . Funciona como uma função aditiva se os dois operandos de uma expressão forem apenas números. O truque é que as matrizes convertem facilmente seus elementos em uma representação de string concatenada.Alguns exemplos:
Há uma boa exceção que
Objects
resulta em duas adiçõesNaN
:fonte
+ '' ou + [] avalia 0.
fonte
[]
é equivalente a . Primeiro, o elemento é extraído e depois convertido por .""
++
Passo a passo disso,
+
vire valor para um número e se você adicionar a uma matriz vazia+[]
... como ela está vazia e é igual a0
, ela seráEntão, a partir daí, agora observe seu código, é
++[[]][+[]]+[+[]]
...E há mais entre eles
++[[]][+[]]
+[+[]]
Então, eles
[+[]]
retornarão[0]
como eles têm uma matriz vazia que é convertida para0
dentro da outra matriz ...Então, como imaginamos, o primeiro valor é uma matriz bidimensional com uma matriz dentro ... então
[[]][+[]]
será igual ao[[]][0]
que retornará[]
...E no final
++
converta e aumente para1
...Então você pode imaginar,
1
+"0"
será"10"
...fonte