2010-08-07 43 views
6

为什么不能使用evalwith声明下访问范围变量?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控制台)。

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

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

在其浏览器中你得到这个行为?你在某个控制台上运行代码吗? – CMS 2010-08-07 19:15:56

+0

@CMS:Chrome 5.0.375.125测试版使用内置的开发者控制台。编辑:我刚刚尝试与Firefox(萤火虫),并按预期工作。必须是您所说的浏览器错误。 – 2010-08-07 19:19:58

+0

@Daniel - 它可以在Chrome 6.0.472.22中正常运行,如果这有助于任何 – 2010-08-07 19:24:47

回答

5

这是一个只能从WebKit的控制台重现的错误,当从FunctionExpression调用eval时,它具有绑定调用者上下文的问题。

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的每夜构建r64893
0

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

+0

不,直接调用'eval'将使用调用上下文(调用者词法和变量环境),间接调用ECMAScript 5中的eval,例如:'var foo = eval; foo('code');'将使用全局上下文以及Function构造函数。 – CMS 2010-08-07 19:50:22

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控制台却没有)。它可能是一个错误或(更可能)它可能按预期工作。

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); 
    } 
} 
+0

请注意,* fallback函数*不符合标准,它不能预先填充或* curry *具有已知参数的函数。 [这个实现](http://stackoverflow.com/questions/2025789/preserving-a-reference-to-this-in-javascript-prototype-functions/2025839#2025839)是最接近你可以遵守的ES5规格,运行在ES3引擎上。另外* binding *函数不会访问调用者的变量或词法环境(看起来OP最终需要),它只能确保'this'值(和* curried *参数)将被持久化。 – CMS 2010-08-08 01:23:47