How come eval doesn't have access to the scoped variables under a with statement?

大兔子大兔子 提交于 2019-12-23 08:26:59

问题


Why can't you access scoped variables using eval under a with statement?

For example:

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

EDIT: As the knowledgeable CMS pointed out, this appears to be a browser bug (browsers that use the WebKit console).

If anyone was wondering what abomination I was trying to come up with that would require both the "evil" eval and with -- I was trying to see if I could get a function (used as a callback) executed in another context rather than the one it was defined in. And no, I probably (cough) won't use this anywhere.. more curious than anything.

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

回答1:


This is a bug reproducible only from the WebKit's Console, it has problems binding the caller context when eval is invoked from a FunctionExpression.

When a direct call of eval is made, the evaluated code as you expect should share both the variable environment:

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

And also the lexical environment:

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

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

In the above function localVar should be declared on the lexical environment of the caller, not on the global context.

For FunctionDeclarations the behavior is completely normal, if we try:

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

And

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

I have been able to reproduce the problem on the following browsers running on Windows Vista SP2:

  • Chrome 5.0.375.125
  • Chrome 6.0.472.25 dev
  • Safari 5.0.1
  • WebKit Nightly Build r64893



回答2:


(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")

All work fine: http://polyfx.com/jstest.html in FF/Chrome/Safari/IE.

The problem with running snippets of code from various consoles is that the consoles usually screw with the context. (i.e. the Chrome console doesn't appear to be properly wrapping stuff in the global context, whereas the Firebug console does). It could be a bug or (more likely) it could be working as intended.




回答3:


Eval always runs in global scope, doesn't it?




回答4:


Putting eval and with aside, new bowsers include the ecma5 Function.prototype.bind method to call a function in some selected object's scope.

For older browsers you can fake it-

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


来源:https://stackoverflow.com/questions/3431689/how-come-eval-doesnt-have-access-to-the-scoped-variables-under-a-with-statement

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!