5

Is there any reason why should this line of code fail?

new Function("eval('function foo(){ alert() }'); foo()")()

It pops an alert in Chromium as expected, but fails in Firefox (foo is not defined). Is this a Firefox bug, or is there something wrong with my code?

user2345215
  • 637
  • 5
  • 9
  • This sounds like a strict/non strict mode thing - are you _sure_ you ran both of them in non-strict mode? (Chrome's behavior) or strict mode (Firefox's)? (Update: looking at the spec this might be an es5 vs es2015 (es6) thing) – Benjamin Gruenbaum May 18 '15 at 23:14
  • @BenjaminGruenbaum I thought about that. I'm pretty sure I ran both in nonstrict mode. But strict mode shouldn't have any effect anyway, as new Function shouldn't reflect that (unlike a regular function). – user2345215 May 18 '15 at 23:16
  • While it's interesting that browsers behave differently, I still am left wondering "why do we care?" XD – Niet the Dark Absol May 18 '15 at 23:16
  • @NiettheDarkAbsol I actually need this for executing nonstrict code inside a strict code block. But eval has betrayed me... (I know I could replace new Function by an indirect eval call, but that looks kind of ugly) – user2345215 May 18 '15 at 23:17
  • @user2345215 yes, this is not a strict mode issue, this is a `Function` constructor scoping issue and possibly a global execution context one. The semantics of what gets put on the global execution context changed I believe in some edge cases between es5 and es2015 (es6) and this might be it. I guess we'll have to check the spec for a sure answer and file a bug (or find the bug) against the offending browsers. – Benjamin Gruenbaum May 18 '15 at 23:17
  • This logs "object" indicating it runs in non-strict mode: `new Function("eval('function foo(){ alert(typeof this) }'); foo.call(6)")()` in chrome (in the console), the same for `new Function("eval('(function foo(){ alert(`type` + typeof this) })').call(6)")()` in firefox - so both browsers run this (correctly) in sloppy mode - now the issue is probably how function declarations are executed in eval in terms of scoping, I'll check the spec – Benjamin Gruenbaum May 18 '15 at 23:23
  • 2
    Ok, I have no idea why firefox is doing this - both [es5](http://www.ecma-international.org/ecma-262/5.1/#sec-10.4.2) and [es6](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-functiondeclarationinstantiation) (see 30 b in the section) say Chrome is right here unless I'm reading something wrong. – Benjamin Gruenbaum May 18 '15 at 23:27
  • @BenjaminGruenbaum Thank you for the references. I would certainly expect a direct nonstrict eval call to define foo in the eval's scope. But Javascript has surprised me many times before, so I wouldn't even ask this had the browsers behaved consistently. I guess Firefox is to blame then. – user2345215 May 18 '15 at 23:48
  • I'm not 100% sure yet - the ES2015 (es6) spec is pretty messy and to be fair these corners are almost never really explored - you can ask on esdiscuss (I can do it for you but I think you'd enjoy the interaction) and get a straight answer from the language lawyers. What do you say? – Benjamin Gruenbaum May 18 '15 at 23:50
  • @BenjaminGruenbaum: My language lawyer feels that this is a Firefox bug. Neither in ES5 nor ES6 an evaled plain function declaration would not be usable there. – Bergi May 19 '15 at 03:26
  • 3
    It indeed is as I have found the bug report https://bugzilla.mozilla.org/show_bug.cgi?id=915805 It's almost 2 years old, so I don't expect this to be fixed anytime soon. – user2345215 May 19 '15 at 12:58
  • @user2345215: You should [make that an answer](http://stackoverflow.com/help/self-answer)! – Bergi May 21 '15 at 20:55
  • 1
    @Bergi I did something better. I fixed it. It's currently in the nightly build. I'll wait a few days just to be safe and then post an answer. – user2345215 Jun 19 '15 at 17:10
  • @user2345215: Wow, thanks! – Bergi Jun 19 '15 at 18:36

1 Answers1

-1

The problem is that eval does not inherit the global scope, so foo is created in a different scope than where it is being called. You can solve this by specifying the scope explicitly, either at the function definition or by passing to eval. I.e. both of the following snippets work as expected:

new Function("eval('window.foo = function(){ alert() }'); foo()")()

new Function("eval('function foo(){ alert() }', this); foo()")()

This behaviour seems to be related to strict mode, as explained by the answer here "use strict"; + jQuery.getScript() = script can't export to global namespace.

Community
  • 1
  • 1
taddeus
  • 102
  • 3
  • 1
    `eval` is not intended to use the global scope, but the local function scope from that it was called (and in that `foo()` is called). Also your second snippet doesn't make sense, `eval` doesnot take a second parameter. – Bergi Jun 16 '15 at 02:52
  • It does actually https://dev.mozilla.jp/localmdc/localmdc_3355.html. However the second argument seems to have been deprecated, so one should not rely on it being implemented (although I tested it in the latest version of Firefox and it works) – taddeus Jun 17 '15 at 07:55