Vamos jogar um pouco mais!
Primeiro, vamos nos divertir!
//----------#01#-----------
{}[true]; //[true]
//----------#02#-----------
var a = {}[true];
console.log(a); //undefined
//----------#03#-----------
{ b: 12345 }[true]; //[true]
//----------#04#-----------
{ b: 12345 }["b"]; //evaluates to ["b"] ?!?
//----------#05#-----------
{ b: 12345 }.b; // "Unexpected token ."
//----------#06#-----------
({ b: 12345 }).b; //12345
//----------#07#-----------
var c = { b: 12345 }.b;
console.log(c); //12345
//----------#08#-----------
var c = { b: 12345 }["b"];
console.log(c); //12345
//----------#09#-----------
{ true: 54321 }[true]; // "SyntaxError: Unexpected token : "
//----------#10#-----------
var d = { true: 54321 }[true]; //No error here ¬¬
console.log(d); //54321
//----------#11#-----------
!{}[true]; // true
Ok, vamos tentar entender esses comportamentos malucos, um por um:
1) Aqui, o {}
é analisado como um bloco de código vazio. Sem uma atribuição, negação, agrupamento (entre parênteses) ou qualquer sintaxe que indique ao analisador que este {}
é um objeto literal, a suposição padrão é pensar que é simplesmente um bloco vazio inútil.
Esta é uma prova desse comportamento:
{ alert(123) }[true]
O código acima mostrará o alerta normalmente e será avaliado como [true]
, da mesma maneira que {}[true]
é.
Declarações de bloco sem ponto e vírgula
Uma instrução do tipo bloco não precisa de um ponto e vírgula após ela.
Por exemplo:
for(var i=0; i < 1; i++){}function a(){};alert("Passed here!");if(true){}alert("Passed here too!")
Os dois alertas são mostrados.
Portanto, podemos ver que uma declaração de bloco vazio, sem ponto e vírgula, é válida e simplesmente não faz nada. Dessa forma, quando você entra {}[true]
no console das Ferramentas do desenvolvedor (ou Firebug), o valor avaliado será o valor da última declaração de expressão . Neste caso, a última declaração expressão é [true]
.
2) Em um contexto de atribuição, o analisador garantirá que {}
seja um objeto literal. Ao fazer var a = {}[true]
, você remove qualquer ambiguidade e informa o analisador que {}
não é uma instrução de bloco.
Então, aqui, você está tentando obter um valor com uma chave "true"
de um objeto vazio. Obviamente, não há par de valores-chave com esse nome de chave. Dessa forma, a variável a é indefinida.
Palavras reservadas como chaves de objeto
O ECMAScript 5 permite que as chaves do objeto sejam palavras reservadas. Portanto, as seguintes chaves são legais:
var obj = {if: 111, for: 222, switch: 333, function: 444, true: 555}
3) A mesma explicação do exemplo 1 . Mas ... Se a { b: 12345 }
peça é tratada como uma declaração de bloco, qual é o tipo da b: 12345
declaração?
... (?????)
É uma declaração de etiqueta , você já a viu antes ... É usada em loops e in switch
. Aqui estão alguns links interessantes sobre instruções de rótulo: 1 , (2) [ Melhor maneira de interromper loops aninhados em Javascript? , (3) [ Como quebrar loops aninhados em javascript? .
NOTA: Apenas tente avaliar isso:
{a: 1, b: 2} //=>>>SyntaxError: Unexpected token :
As instruções do rótulo não podem ser separadas pelo operador de vírgula ; você precisará separá-las com um ponto e vírgula. Portanto, isso é válido:{a: 1; b: 2}
4) Veja as explicações para os exemplos 1 e 3 ...
5) Mais uma vez, estamos { b: 12345 }
sendo tratados como um bloco de código e você está tentando acessar uma propriedade de um bloco de código usando a notação de ponto e, obviamente, isso não é permitido, e o analisador lança um"Unexpected token :"
exceção.
6) O código é quase idêntico ao exemplo acima, mas cercando a { b: 12345 }
instrução com o operador de agrupamento de expressões , o analisador saberá que é um objeto. Dessa forma, você poderá acessar o"b"
propriedade normalmente.
7) Lembre-se do exemplo 2 , temos uma atribuição aqui, o analisador sabe que{ b: 12345 }
é um objeto.
8) Idêntico ao exemplo acima, mas em vez da notação de ponto, aqui estamos usando a notação de colchete .
9) Eu já disse que essa "identifier: value"
sintaxe dentro de uma instrução de bloco é um rótulo. Mas você também deve saber que um nome de rótulo não pode ser uma palavra-chave reservada (o oposto dos nomes de propriedades do objeto). Quando tentamos definir um rótulo chamado "true"
, obtivemos a SyntaxError
.
10) Mais uma vez, estamos lidando com um objeto. Não há problemas ao usar palavras reservadas aqui. =)
11) Finalmente, temos o seguinte:!{}[true]
Vamos separar as coisas aqui:
a) Ao fazer uma negação, informamos ao analisador que {}
é um objeto .
b) Como mostrado no exemplo 2 , um {}
objeto não possui uma propriedade chamada true
, portanto, essa expressão será avaliada comoundefined
.
c) O resultado final é a negação de undefined
valor. Javascript realiza conversão de tipo implícito , e o undefined
valor é falso .
d) Então, a negação de false
é ... true
!
var o = {}; o[true] === undefined
.