Как именно разбирается выражение JavaScript [1 [{}]]? - PullRequest
6 голосов
/ 21 июня 2010

Можете ли вы объяснить, как выражение JavaScript:

[1 [{}]]

анализирует / оценивает?В Firefox, Chrome, Konqueror и Rhino создается массив с одним элементом undefined.Однако я не понимаю, почему.

В Firefox:

[1 [{}]].toSource()

производит

[(void 0)]

Замена 1 другими значениями JavaScript, похоже, дает тот же результат.

Обновление: Iкажется, я понимаю сейчас.Кодека, Адриан и CMS прояснили.Что касается стандарта, я попытался пройтись по ECMAScript 5.

  1. 1 [{}] - это средство доступа к свойствам, поэтому он рассматривается в §11.2.1.
  2. baseReferenceрезультат оценки 1, поэтому все еще 1.
  3. baseValue = GetValue(baseReference) == 1.
  4. При GetValue (§8.7.1), Type(1) не равно Reference (разрешенная привязка имени), поэтому возвращаемое значение 1.
  5. propertyNameReference является результатом вычисления {}, поэтому пустой объект.
  6. propertyNameValue = GetValue(propertyNameReference) == {}
  7. В CheckObjectCoercible(baseValue) (§9.10), мы возвращаемся (Число является объектно-принудительным).
  8. propertyNameString = ToString(propertyNameValue)
  9. В ToString (§9.8), возвращаем ToString(ToPrimitive({}, hint String))
  10. В ToPrimitive (§9.1) возвращают результат [[DefaultValue]] объекта, передавая PreferredType (строка).
  11. В [[DefaultValue]] (§8.12.8), пусть toString будет результатом [[Get]]с аргументом toString.
  12. Это определено в §15.2.4.2 для возврата "[object " + [[Class]] + "]", где [[Class]] - «Объект» для прототипа объекта по умолчанию.
  13. Поскольку существует вызываемый toString, мы вызываем его с аргументом this, являющимся {}.
  14. Возвращаем значение типа Reference, базовое значение которого BaseValue(1) и чье ссылочное имя propertyNameString ("[object Object]").

Затем мы переходим к инициализатору массива (§11.1.4) и создаем массив из одного элемента с результатом.

Ответы [ 3 ]

15 голосов
/ 21 июня 2010

Читая комментарии OP и Ника , я думаю, что могу немного расширить ответ Адриана , чтобы сделать его более понятным.

Это совершенно правильный JavaScript.

JavaScript обрабатывает имена свойств объекта как строки, объекты не могут содержать другие типы или другие объекты как ключи , они просто строки.

Обозначение в скобках свойство accessor (MemberExpression [ Expression ]) неявно преобразует выражение в скобках в строку, поэтому:

var obj = {};
obj[{}] = "foo";
alert(obj["[object Object]"]); // foo

В приведенном выше примере вы видите, что я присваиваю значение свойству {}, а {}.toString() (или {}+'') создает строку "[object Object] (через Object.prototype.toString) .

Выражение 1 [{}] неявно преобразует примитив 1 Number в объект (это делается средством доступа к свойству), и он ищет свойство с именем "[object Object]", поиск свойства выполняется на Number.prototype и Object.prototype объектов, например:

1['toString'] === Number.prototype.toString; // true

Наконец, выражение 1 [{}] заключено в квадратные скобки ([1 [{}]]), на самом деле это литерал Array.

В заключение вот как анализатор вычисляет выражение:

 [1 [{}]];
 //   ^ The accessor expression is evaluated and converted to string

 [1 ["[object Object]"]];
 // ^ A property lookup is made on an Number object 
 //   trying to access a property named "[object Object]"

 [undefined];
 //   ^ the property is obviously not found

   [undefined];
 //^         ^
 // An array literal is created with an element `0` which its value is `undefined`
8 голосов
/ 21 июня 2010

Это потому, что вы пытаетесь получить свойство {} объекта 1 и затем поместить его в массив. 1 не имеет свойства {}, поэтому 1[{}] равно undefined.

Если вы замените 1 на массив, вы увидите, как он работает. С 1 как [5] и {} как 0, это [[5][0]].

Также имейте в виду, что obj['property'] совпадает с obj.property.

7 голосов
/ 21 июня 2010

Если немного разбить, вы увидите:

var foo = 1;
var bar = {};
var baz = foo[bar];

[baz];

Я верю, что это правильный JavaScript, но я не эксперт ...

...