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

почему вы не можете получить доступ к переменным области с помощью 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 -- Я пытался увидеть, могу ли я получить функцию (используется как обратный вызов) выполняется в другом контексте, а не в том, в котором он был определен. И нет, я!--7-->наверное (кашель) не будет использовать это нигде.. любопытнее всего.

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

4 ответов


это ошибка, воспроизводимая только с консоли 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 должно быть объявлено в лексической среде вызывающего абонента, а не в глобальной контекст.

на FunctionDeclarations поведение совершенно нормально, если мы попробуем:

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

(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 делает). Это может быть ошибка или (что более вероятно) она может работать по назначению.


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


Кладущ eval и С в сторону, новые bowsers включают функцию ecma5.прототип.метод bind для вызова функции в области выбранного объекта.

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

Function.prototype.bind= Function.prototype.bind || function bind(scope){
    var method= this;
    return function(){
        method.apply(scope, arguments);
    }
}