Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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); })
like image 462
Cristian Sanchez Avatar asked Aug 07 '10 19:08

Cristian Sanchez


People also ask

Why eval should not be used?

Malicious code : invoking eval can crash a computer. For example: if you use eval server-side and a mischievous user decides to use an infinite loop as their username. Terribly slow : the JavaScript language is designed to use the full gamut of JavaScript types (numbers, functions, objects, etc)… Not just strings!

What is a safe alternative to using eval ()?

An alternative to eval is Function() . Just like eval() , Function() takes some expression as a string for execution, except, rather than outputting the result directly, it returns an anonymous function to you that you can call. `Function() is a faster and more secure alternative to eval().

How does eval work in JavaScript?

eval() is a function property of the global object. The argument of the eval() function is a string. It will evaluate the source string as a script body, which means both statements and expressions are allowed. It returns the completion value of the code.

What is $$ eval?

$$eval() method. This method runs Array. from(document. querySelectorAll(selector)) within the page and passes the result as the first argument to the pageFunction .


1 Answers

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
like image 182
Christian C. Salvadó Avatar answered Sep 18 '22 23:09

Christian C. Salvadó