Давай поиграем еще немного!
Во-первых, повеселимся !:
//----------#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
Хорошо, давайте попробуем разобраться в этом безумном поведении, одно за другим:
1) Здесь {}анализируется как пустой блок кода. Без присваивания, отрицания, группировки (в круглых скобках) или любого синтаксиса, который указывает парсеру, что это {}литерал объекта, по умолчанию предполагается, что это просто бесполезный пустой блок.
Это доказательство такого поведения:
{ alert(123) }[true]
Приведенный выше код покажет предупреждение в обычном режиме и будет оцениваться так [true]же, как {}[true]и.
Блокировать заявления без точки с запятой
Оператор блочного типа не требует точки с запятой после него.
Например:
for(var i=0; i < 1; i++){}function a(){};alert("Passed here!");if(true){}alert("Passed here too!")
Отображаются оба предупреждения.
Итак, мы можем видеть, что оператор пустого блока без точки с запятой действителен и просто ничего не делает. Таким образом, когда вы входите {}[true]в консоль Developer Tools (или Firebug), оцененное значение будет значением последнего оператора выражения . В этом случае последний оператор выражения - [true].
2) В контексте присваивания синтаксический анализатор убедится, что {}это литерал объекта. Когда вы делаете var a = {}[true], вы устраняете любую двусмысленность и отключаете синтаксический анализатор, который {}не является оператором блока.
Итак, здесь вы пытаетесь получить значение с помощью ключа "true"из пустого объекта. Очевидно, что с этим именем ключа не существует пары "ключ-значение". Таким образом, переменная не определена.
Зарезервированные слова как ключи объекта
ECMAScript 5 позволяет объектным ключам быть зарезервированными словами. Итак, следующие ключи допустимы:
var obj = {if: 111, for: 222, switch: 333, function: 444, true: 555}
3) То же объяснение примера 1 . Но ... Если { b: 12345 }часть трактуется как оператор блока, какой тип b: 12345оператора ??
... (?????)
Это оператор метки , вы уже видели его раньше ... Он используется в циклах и in switch. Вот несколько интересных ссылок об операторах меток: 1 , (2) [ Лучший способ выйти из вложенных циклов в Javascript? , (3) [ Как разбить вложенные циклы в javascript? ,
ПРИМЕЧАНИЕ: просто попробуйте оценить это:
{a: 1, b: 2} //=>>>SyntaxError: Unexpected token :
Операторы меток не могут быть разделены оператором запятой , вам нужно будет разделить их точкой с запятой. Итак, это действительно так:{a: 1; b: 2}
4) См. Пояснения к примерам 1 и 3 ...
5) Еще раз, у нас есть { b: 12345 }обработка как блок кода, и вы пытаетесь получить доступ к свойству блока кода, используя точечную нотацию , и, очевидно, это не разрешено, и синтаксический анализатор выдает "Unexpected token :"исключение.
6) Код практически идентичен приведенному выше примеру, но окружая { b: 12345 }заявление с оператором выражения группирования , анализатор будет знать , что является объектом. Таким образом, вы сможете получить доступ к "b"собственности в обычном режиме.
7) Помните пример 2 , здесь у нас есть присваивание, парсер знает, что { b: 12345 }это объект.
8) Идентично приведенному выше примеру, но вместо точечной записи мы используем скобки .
9) Я уже сказал, что этот "identifier: value"синтаксис внутри оператора блока является меткой. Но вы также должны знать, что имя метки не может быть зарезервированным ключевым словом (противоположным именам свойств объекта). Когда мы попытались определить метку с именем "true", мы получили SyntaxError.
10) Опять же, мы имеем дело с объектом. Здесь нет проблем с использованием зарезервированных слов. знак равно
11) Наконец, у нас есть это:!{}[true]
Давайте разделим вещи здесь:
а) Делая отрицание, мы информируя анализатор , что {}является объектом .
б) Как показано в примере 2 , {}объект не имеет вызываемого свойства true, поэтому это выражение будет оцениваться как undefined.
в) Конечный результат - отрицание undefinedценности. Javascript выполняет неявное преобразование типов , а undefinedзначение является ложным .
г) Итак, отрицание false... true!
var o = {}; o[true] === undefined,