javascript - with - new html element jquery




Por que++[[]][+[]]+[+[]] retorna a string “10”? (6)

Isso é válido e retorna a string "10" em JavaScript ( mais exemplos aqui ):

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

Por quê? O que esta acontecendo aqui?


  1. Cadeia unária mais dada converte em número
  2. Incrementar operador dado string converte e incrementa em 1
  3. [] == ''. Corda Vazia
  4. + '' ou + [] avalia 0.

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

+ [] é avaliado como 0 [...] e então a soma (+ operação) com qualquer coisa converte o conteúdo da matriz em sua representação de string consistindo em elementos unidos com vírgula.

Qualquer outra coisa, como pegar o índice de array (ter maior prioridade que a operação +) é ordinal e não é nada interessante.


O seguinte é adaptado de uma postagem no blog respondendo a essa pergunta que eu publiquei enquanto essa questão ainda estava encerrada. Os links são para (uma cópia em HTML) da especificação ECMAScript 3, ainda a linha de base para JavaScript nos navegadores da Web usados ​​atualmente.

Primeiro, um comentário: esse tipo de expressão nunca vai aparecer em nenhum ambiente de produção (sã) e serve apenas como um exercício de quão bem o leitor conhece as bordas sujas do JavaScript. O princípio geral de que operadores JavaScript convertem implicitamente entre tipos é útil, assim como algumas das conversões comuns, mas grande parte dos detalhes, neste caso, não é.

A expressão ++[[]][+[]]+[+[]] pode inicialmente parecer bastante imponente e obscura, mas na verdade é relativamente fácil decompor 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 . Então, a expressão pode ser mais claramente escrita como

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

Quebrando isso, podemos simplificar observando que +[] avaliado como 0 . Para se certificar por que isso é verdade, confira o operador unary + e siga a trilha levemente tortuosa que termina com ToPrimitive convertendo o array vazio em uma string vazia, que é finalmente convertida em 0 por ToNumber . Podemos agora substituir 0 por cada instância de +[] :

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

Mais simples já. Quanto a ++[[]][0] , essa é uma combinação do bclary.com/2004/11/07/#a-11.4.4 ( ++ ), um literal de matriz definindo uma matriz com um único elemento que é um array vazio ( [[]] ) e um acessador de propriedade ( [0] ) chamou a matriz definida pelo literal da matriz.

Então, podemos simplificar [[]][0] para apenas [] e temos ++[] , certo? De fato, este não é o caso porque avaliar ++[] gera um erro, que inicialmente pode parecer confuso. No entanto, um pouco de reflexão sobre a natureza do ++ deixa isso claro: ele é usado para incrementar uma variável (por exemplo, ++i ) ou uma propriedade de objeto (por exemplo, ++obj.count ). Não só avalia um valor, como também armazena esse valor em algum lugar. No caso de ++[] , 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, que é chamada pelo operador de incremento de prefixo.

Então, o que faz ++[[]][0] ? Bem, por lógica similar a +[] , a matriz interna é convertida em 0 e este valor é incrementado em 1 para nos dar um valor final de 1 . O valor da propriedade 0 na matriz externa é atualizado para 1 e a expressão inteira é avaliada como 1 .

Isso nos deixa com

1 + [0]

... o que é um simples uso do operador de adição . Os dois operandos são primeiro ToPrimitive e, se o valor primitivo for uma cadeia, a concatenação de cadeias será executada, caso contrário, a adição numérica será executada. [0] converte para "0" , então a concatenação de strings é usada, produzindo "10" .

Como um aparte final, algo que pode não ser imediatamente aparente é que sobrescrever um dos métodos toString() ou valueOf() de Array.prototype irá mudar o resultado da expressão, porque ambos são verificados e usados ​​se estiverem presentes na conversão de uma expressão. objeto em um valor primitivo. Por exemplo, o seguinte

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

... produz "NaNfoo" . Por que isso acontece é deixado como um exercício para o leitor ...


Se dividirmos, a bagunça é igual a:

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

Em JavaScript, é verdade que +[] === 0 . + converte algo em um número e, nesse caso, ele será reduzido para +"" ou 0 (consulte os detalhes da especificação abaixo).

Portanto, podemos simplificá-lo ( ++ tem precendence over + ):

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

Porque [[]][0] significa: obter o primeiro elemento de [[]] , é verdade que:

  • [[]][0] retorna a matriz interna ( [] ). Devido a referências, é errado dizer [[]][0] === [] , mas vamos chamar o array interno A para evitar a notação errada.
  • ++[[]][0] == A + 1 , uma vez que ++ significa 'incremento por um'.
  • ++[[]][0] === +(A + 1) ; em outras palavras, sempre será um número ( +1 não necessariamente retorna um número, enquanto ++ sempre faz - graças a Tim Down por apontar isto).

Mais uma vez, podemos simplificar a bagunça em algo mais legível. Vamos substituir [] volta por A :

+([] + 1)
+
[0]

Em JavaScript, isso também é verdade: [] + 1 === "1" , porque [] == "" (unindo uma matriz vazia), então:

  • +([] + 1) === +("" + 1) e
  • +("" + 1) === +("1") e
  • +("1") === 1

Vamos simplificar ainda mais:

1
+
[0]

Além disso, isso é verdade em JavaScript: [0] == "0" , porque está unindo uma matriz a um elemento. A junção irá concatenar os elementos separados por. Com um elemento, você pode deduzir que essa lógica resultará no primeiro elemento em si.

Então, no final nós obtemos (number + string = string):

1
+
"0"

=== "10" // Yay!

Detalhes da especificação para +[] :

Isso é bem um labirinto, mas para fazer +[] , primeiro ele está sendo convertido em uma string porque é o que + diz:

11.4.6 Operador Unary +

O operador unário + converte seu operando em tipo de número.

A produção UnaryExpression: + UnaryExpression é avaliada da seguinte maneira:

  1. Deixe expr ser o resultado da avaliação de UnaryExpression.

  2. Retornar paraNúmero (GetValue (expr)).

ToNumber() diz:

Objeto

Aplique as seguintes etapas:

  1. Deixe primValue ser ToPrimitive (argumento de entrada, hint String).

  2. Retornar ToString (primValue).

ToPrimitive() diz:

Objeto

Retorna um valor padrão para o objeto. O valor padrão de um objeto é recuperado chamando o método interno [[DefaultValue]] do objeto, passando a dica opcional PreferredType. O comportamento do método interno [[DefaultValue]] é definido por esta especificação para todos os objetos ECMAScript nativos em 8.12.8.

[[DefaultValue]] diz:

8.12.8 [[DefaultValue]] (sugestão)

Quando o método interno de [[DefaultValue]] de O é chamado com a string hint, as seguintes etapas são executadas:

  1. Deixe que toString seja o resultado de chamar o método interno [[Get]] do objeto O com o argumento "toString".

  2. Se IsCallable (toString) for true,

uma. Deixe str ser o resultado de chamar o método interno de [[Call]] de toString, com O como este valor e uma lista de argumentos vazia.

b. Se str é um valor primitivo, retorne str.

O .toString de uma matriz diz:

15.4.4.2 Array.prototype.toString ()

Quando o método toString é chamado, as seguintes etapas são executadas:

  1. Deixe array ser o resultado de chamar ToObject no valor this.

  2. Deixe func ser o resultado de chamar o método interno de array [[Get]] com o argumento "join".

  3. Se IsCallable (func) for falso, então let func ser o método interno padrão Object.prototype.toString (15.2.4.2).

  4. Retorna o resultado de chamar o método interno [[Chamada]] de func fornecendo matriz como o valor e uma lista de argumentos vazia.

Então +[] se reduz a +"" , porque [].join() === "" .

Novamente, o + é definido como:

11.4.6 Operador Unary +

O operador unário + converte seu operando em tipo de número.

A produção UnaryExpression: + UnaryExpression é avaliada da seguinte maneira:

  1. Deixe expr ser o resultado da avaliação de UnaryExpression.

  2. Retornar paraNúmero (GetValue (expr)).

ToNumber está definido para "" como:

O MV de StringNumericLiteral ::: [empty] é 0.

Então +"" === 0 e, portanto, +[] === 0 .


Vamos simplificar:

++[[]][+[]]+[+[]] = "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"

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

Então nós temos uma concatenação de string

1+[0].toString() = 10




syntax