EcmaScript 5 Google TechTalk - пример случайного столкновения 1 - PullRequest
5 голосов
/ 05 марта 2011

Я смотрю эту лекцию: http://www.youtube.com/watch?v=Kq4FpMe6cRs

image

// the speaker states that "'bar' is just some function 
// that invokes whatever function is passed to it"
function bar(fn) {
    fn();
}

function foo() {
    var x = 8;
    bar(function baz() { return x; });
}

Object.prototype.x = 'foo';

На 35-й минуте показан вышеописанный вопрос.Лектор утверждает, что некоторые браузеры будут возвращать foo вместо 8.

Почему?

Кстати, когда я писал этот вопрос, я разобрался с ним, но я все равно опубликую этот вопрос, потому что это интересная проблема.:)


Демонстрационная версия: http://jsfiddle.net/simevidas/mHyKc/

Оповещения Opera 11 'foo', все остальные мои браузеры (включая IE9) возвращают 8.


Обновление: Я забираю то, что я сказал о том, что понял это.Это как-то связано с тем, что вложенная функция является именованной функцией.Если вы удалите имя (baz), то Opera вернет 8, что означает, что проблема возникает только с именованными вложенными функциями.

Но почему?

1 Ответ

4 голосов
/ 05 марта 2011

Я признаю, что искал это. Я не думаю, что понял бы это так легко, если не сказать больше. http://kangax.github.com/nfe/#spidermonkey-peculiarity

Чтобы понять проблему, необходима семантика выражений именованных функций. Чтобы процитировать ссылку, «идентификатор выражения именованной функции доступен только для локальной области видимости функции». Конкретно это означает:

var fn = function aNamedFunction() {
  typeof aNamedFunction;  // "function"
};
typeof aNamedFunction;  // "undefined"

Чтобы реализовать это поведение, SpiderMonkey и другие механизмы JS создают фиктивный фрейм среды между родительским фреймом (т. Е. Областью действия, в которой определяется функция) и внутренним фреймом функции, который создается каждый время, когда функция вызывается. Этот фиктивный фрейм построен, как если бы был вызван new Object(), и содержит отображение из aNamedFunction в сам объект функции.

В примере кода вопроса x разрешается, сначала посмотрев в самый внутренний фрейм вызова функции. Поскольку тело функции не объявляет var x;, оно не найдено, и интерпретатор проверяет кадр на один уровень вверх, который является фиктивным кадром. Поскольку фиктивный фрейм был создан new Object() (или чем-то семантически эквивалентным), поиск x в фиктивном фрейме будет проходить по цепочке прототипов, как и для любого другого объекта JavaScript. Таким образом, он ищет Object.prototype, находит строку 'foo', связанную с x, и возвращает ее.

Слава Богу, за последовательное лексическое определение ES5.

Альтернативное чтение: http://dmitrysoshnikov.com/ecmascript/chapter-5-functions/#nfe-and-spidermonkey

...