Почему у eval нет доступа к переменным в области видимости с оператором with? - PullRequest
7 голосов
/ 07 августа 2010

Почему не может получить доступ к переменным в области, используя eval в операторе with?

Например:

(function (obj) { 
   with (obj) {
      console.log(a); // prints out obj.a
      eval("console.log(a)"); // ReferenceError: a is not defined
   }
})({ a: "hello" })

РЕДАКТИРОВАТЬ: Как указала знающая CMS, это, похоже, ошибка браузера (браузеры, использующие консоль WebKit).

Если кому-то интересно, какую мерзость я пытался придумать, это потребует как«зло» eval и with - я пытался выяснить, могу ли я получить функцию (используемую в качестве обратного вызова), выполненную в другом контексте, а не в том, в котором она была определена. И нет, я вероятно, (кашель) не будет нигде использовать это ... более любопытно, чем что-либо.

(function (context,fn) { 
    with (context) 
       eval("("+fn+")()"); 
})({ a: "hello there" }, function () { console.log(a); })

Ответы [ 4 ]

6 голосов
/ 08 августа 2010

Это ошибка, воспроизводимая только из консоли WebKit, у нее возникают проблемы с привязкой контекста вызывающей стороны, когда eval вызывается из FunctionExpression.

Когда выполняется прямой вызов eval, оцененный код, как вы ожидаете, должен совместно использовать обе переменные среды:

(function (arg) {
  return eval('arg');
})('foo');
// should return 'foo', throws a ReferenceError from the WebKit console

А также лексическая среда:

(function () {
  eval('var localVar = "test"');
})();

typeof localVar; // should be 'undefined', returns 'string' on the Console

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

Для FunctionDeclaration s поведение абсолютно нормальное, если мы попробуем:

function test1(arg) {
  return eval('arg');
}
test1('foo'); // properly returns 'foo' on the WebKit console

И

function test2() {
  eval('var localVarTest = "test"');
}
test2();
typeof localVarTest; // correctly returns 'undefined'

Мне удалось воспроизвести проблему в следующих браузерах, работающих под управлением Windows Vista SP2:

  • Chrome 5.0.375.125
  • Chrome 6.0.472.25 dev
  • Safari 5.0.1
  • WebKit Nightly Build r64893
1 голос
/ 08 августа 2010
(function (obj) {
   with (obj) {
      alert(a); // prints out obj.a
      eval("alert(a)"); // ReferenceError: a is not defined
   }
})({ a: "hello from a with eval" })

function testfunc(a) { eval("alert(a)"); } testfunc("hello from a testfunc eval");

(function (a) { eval("alert(a)"); })("hello from a function constructor eval")

Все отлично работает: http://polyfx.com/jstest.html в FF / Chrome / Safari / IE.

Проблема с запуском фрагментов кода из разных консолей заключается в том, что консоли обычно связаны с контекстом. (то есть консоль Chrome, по-видимому, неправильно упаковывает вещи в глобальном контексте, в то время как консоль Firebug делает это). Это может быть ошибка или (что более вероятно), она может работать как задумано.

0 голосов
/ 08 августа 2010

Отложив eval и оставив в стороне, новые баузеры включают метод ecma5 Function.prototype.bind для вызова функции в области видимости какого-то выбранного объекта.

Для старых браузеров вы можете подделать его -

Function.prototype.bind= Function.prototype.bind || function bind(scope){
    var method= this;
    return function(){
        method.apply(scope, arguments);
    }
}
0 голосов
/ 07 августа 2010

Eval всегда работает в глобальном масштабе, не так ли?

...