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 e 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); })
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 e 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); })
Share
Improve this question
edited Aug 7, 2010 at 20:02
Cristian Sanchez
asked Aug 7, 2010 at 19:06
Cristian SanchezCristian Sanchez
32.2k11 gold badges58 silver badges63 bronze badges
13
- In which browser are you getting this behavior? Are you running the code on some console? – Christian C. Salvadó Commented Aug 7, 2010 at 19:15
- @CMS: Chrome 5.0.375.125 beta using the built in developer console. Edit: I just tried this with Firefox (firebug) and it worked as expected. Must be a browser bug like you said. – Cristian Sanchez Commented Aug 7, 2010 at 19:19
- @Daniel - It works correctly in Chrome 6.0.472.22 if that helps any – Nick Craver Commented Aug 7, 2010 at 19:24
- @Nick, @Daniel, the problem is present only in the console I get the same behavior on Chrome 6.0.472.25, I'm pretty sure that this issue is somehow related to the WebKit console, because it is also reproducible on Safari 5.0.1 and in a WebKit Nightly build – Christian C. Salvadó Commented Aug 7, 2010 at 19:31
-
It doesn't seem to be limited to the
with
statement either. The simple case:(function (a) { eval("console.log(a)"); })("hello")
also fails. I guess I'll submit the issue unless anyone else wants to. – Cristian Sanchez Commented Aug 7, 2010 at 19:37
4 Answers
Reset to default 6This 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 FunctionDeclaration
s the behavior is pletely 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
(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./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.
Eval always runs in global scope, doesn't it?
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);
}
}