Книга: JavaScript. Подробное руководство, 6-е издание

4.12.2. Использование eval() в глобальном контексте

4.12.2. Использование eval() в глобальном контексте

Способность функции eval() изменять локальные переменные представляет значительную проблему для оптимизаторов JavaScript. Для ее решения некоторые интерпретаторы просто уменьшают степень оптимизации всех функций, вызывающих eval(). Однако как быть интерпретатору JavaScript, когда в сценарии определяется псевдоним функции eval() и выполняется ее вызов по другому имени? Чтобы облегчить жизнь разработчикам интерпретаторов JavaScript, стандарт ECMAScript 3 требует, чтобы такая возможность в интерпретаторах была запрещена. Если функция eval() вызывается под любым другим именем, отличным от «eval», она должна возбуждать исключение EvalError.

Однако большинство разработчиков используют иные решения. При вызове под любым другим именем функция eval() должна выполнять программный код в глобальном контексте. Выполняемый ею программный код может определять новые глобальные переменные или глобальные функции и изменять значения глобальных переменных, но не может использоваться для модификации локальных переменных в вызывающих функциях, благодаря чему устраняются препятствия для локальной оптимизации.

Стандарт ECMAScript 5 отменяет возбуждение исключения EvalError и стандартизует поведение eval(), сложившееся де-факто. «Прямой вызов» - это вызов функции eval() по ее непосредственному имени «eval» (которое все больше начинает походить на зарезервированное слово). Прямые вызовы eval() используют окружение вызывающего контекста. Любые другие вызовы - косвенные вызовы - в качестве окружения используют глобальный объект и не могут получать, изменять или определять локальные переменные или функции. Это поведение демонстрируется в следующем фрагменте:

var geval = eval;         // Другое имя eval для вызова в глобальном контексте
var х = "global", у = "global"; // Две глобальные переменные
function f() { // Вызывает eval в локальном контексте
  var х = "local"; // Определение локальной переменной
  eval("x += 'changed';"); // Прямой вызов eval изменит локальную переменную
  return х; // Вернет измененную локальную переменную
}
function g() {     // Вызывает eval в глобальном контексте
  var у = "local"; // Локальная переменная
  geval("y += 'changed';") // Косвенный вызов eval изменит глоб. переменную
  return y;        // Вернет неизмененную локальную переменную
}
console.log(f(), х); //Изменилась локальная переменная: выведет "localchanged global":
console.log(g(), у); //Изменилась глобальная переменная: выведет "local globalchanged":

Обратите внимание, что обеспечение возможности вызывать функцию eval() в глобальном контексте - это не просто попытка удовлетворить потребности оптимизатора. Фактически это чрезвычайно полезная особенность: она позволяет выполнять строки с программным кодом, как если бы они были независимыми сценариями. Как уже отмечалось в начале этого раздела, действительная необходимость выполнять строки программного кода на практике возникает очень редко. Но если вы сочтете это необходимым, вам, скорее всего, потребуется вызывать функцию eval() именно в глобальном контексте, а не в локальном.

До появления версии IE9 Internet Explorer отличался от других броузеров: функцияeval(), вызванная под другим именем, выполняла переданный ей программный код не в глобальном контексте. (Однако она не возбуждала исключение EvalError: программный код просто выполнялся ею в локальном контексте.) Но IE определяет глобальную функцию execScript(), которая выполняет строку с программным кодом, переданную в виде аргумента, как если бы она была сценарием верхнего уровня. (Однако, в отличие от eval(), функция execScript() всегда возвращаетnull.)

Оглавление книги


Генерация: 2.207. Запросов К БД/Cache: 3 / 1
поделиться
Вверх Вниз