7

What I tried (which works in chrome)

var class_str = "class Test {};";
var a = eval(class_str);
console.log(new a());

Raises following error in Firefox 46:

TypeError: a is not a constructor

a is undefined and using new A() returns ReferenceError: A is not defined.

What is different on Firefox?

previous_developer
  • 10,579
  • 6
  • 41
  • 66
  • just what is returned from eval. try `var class_str = "class Test {}; return Test;";` – Daniel A. White Sep 02 '16 at 18:53
  • It returns `SyntaxError: return not in function` @DanielA.White Chrome does not work that way, too. – previous_developer Sep 02 '16 at 18:56
  • If you type `class Test {};` into the console, you'll see that Firefox gives you `undefined`, while Chrome gives you the class. So Chrome is providing a value for the last statement in the program, while Firefox isn't. Not sure which is correct. Another example of a statement returning a value would be to see the result of a `for` statement using `eval`. `var x = eval("for (var i = 0; i < 10; i++) { i }"); console.log(x); // 9` –  Sep 02 '16 at 18:57
  • @squint Thanks, it turns out I just need to put the whole class in parentheses, as in `(class Test {})` – previous_developer Sep 02 '16 at 19:09
  • Possible duplicate of [Using eval to execute functions](http://stackoverflow.com/q/17447256/1529630) or [How to convert text to a function using JavaScript](http://stackoverflow.com/q/32607273/1529630) – Oriol Sep 02 '16 at 19:36

2 Answers2

12

Putting the whole class string in parentheses works.

Fixed code:

var class_str = "(class Test {})";
var a = eval(class_str);
console.log(new a());
previous_developer
  • 10,579
  • 6
  • 41
  • 66
  • Taking a quick look at the spec, it seems like Firefox may be correct. It looks like there's a distinction between a `class` declaration and expression, much like functions, and the Return of each seems to mirror that of functions, so wrapping in parens would have the same effect of making it an expression. –  Sep 02 '16 at 19:26
  • 1
    @Oriol: Yeah, I saw that too, but then I looked at the next section [14.5.16 Runtime Semantics: Evaluation](http://www.ecma-international.org/ecma-262/6.0/#sec-class-definitions-runtime-semantics-evaluation), under *ClassDeclaration : class BindingIdentifier ClassTail* which calls the section you referenced, and it shows `Return NormalCompletion(empty)`, just like function declarations do. However I'm totally guessing at what `NormalCompletion(empty)` actually means, so I could be wrong. –  Sep 02 '16 at 19:57
  • I think the closest I can find for now is [6 ECMAScript Data Types and Values](http://www.ecma-international.org/ecma-262/6.0/#sec-ecmascript-data-types-and-values), which states *"...When the term “empty” is used as if it was naming a value, it is equivalent to saying “no value of any type”."*. Don't know if that's the right section or not, or if *"no value of any type"* translate to the `Undefined` type eventually. –  Sep 02 '16 at 20:13
  • 1
    @squint You are right, of course. Declarations don't return values, just like statements. They return [completions](http://www.ecma-international.org/ecma-262/6.0/#sec-completion-record-specification-type). `NormalCompletion` means that the code finished without `return`, `break`, etc., and `empty` means no value, which [`eval`](http://www.ecma-international.org/ecma-262/6.0/#sec-performeval) will transform to `undefined`. – Oriol Sep 02 '16 at 20:13
  • @Oriol: So because the completion has a `value`, and the `value` is given `empty`, it must translate to `undefined`, but that's an assumption on my part. I'll check out `eval` quick to see if that's the case. –  Sep 02 '16 at 20:15
  • ...ah, looks like you're way ahead of me! –  Sep 02 '16 at 20:16
3

I tried another method that works just as using parentheses and seems much simpler as it doesn't pollute global names.

result = eval(`class a{} window.a=a`)

console.log(result)
IT goldman
  • 14,885
  • 2
  • 14
  • 28
Vetrivel
  • 306
  • 1
  • 9