7

为什么不能使用evalunderwith语句访问作用域变量?

例如:

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

编辑:正如知识渊博的 CMS 所指出的,这似乎是一个浏览器错误(使用 WebKit 控制台的浏览器)。

如果有人想知道我试图想出什么可憎的东西,这将需要“邪恶”evalwith- 我试图看看我是否可以在另一个上下文而不是它的上下文中执行一个函数(用作回调)被定义了。不,我可能(咳嗽)不会在任何地方使用它......比任何东西都更好奇。

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

4 回答 4

6

这是一个只能从 WebKit 控制台重现的错误,当evalFunctionExpression.

当直接调用 时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 上运行的以下浏览器上重现该问题:

  • 铬 5.0.375.125
  • 铬 6.0.472.25 开发
  • Safari 5.0.1
  • WebKit 每晚构建 r64893
于 2010-08-07T20:25:43.980 回答
1
(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")

一切正常: FF/Chrome/Safari/IE 中的http://polyfx.com/jstest.html

从各种控制台运行代码片段的问题在于,控制台通常会与上下文发生冲突。(即 Chrome 控制台似乎没有在全局上下文中正确地包装东西,而 Firebug 控制台却可以)。这可能是一个错误,或者(更有可能)它可以按预期工作。

于 2010-08-07T20:17:49.067 回答
0

撇开 eval 不谈,新的 bowsers 包括 ecma5 Function.prototype.bind 方法来调用某些选定对象范围内的函数。

对于较旧的浏览器,您可以伪造它-

Function.prototype.bind= Function.prototype.bind || function bind(scope){
    var method= this;
    return function(){
        method.apply(scope, arguments);
    }
}
于 2010-08-07T23:52:05.753 回答
0

eval 总是在全局范围内运行,不是吗?

于 2010-08-07T19:45:03.190 回答