0

As per the Mozilla docs in order to execute a function using eval it must be wrapped inside ( ) i.e. if you don't use them then it treated as a string.

eval as a string defining function requires "(" and ")" as prefix and suffix

when I execute normal function it returns undefined as expected but not in the case of ES6 functions. My Question is ES6 functions are treated differently by javascript engines or only within eval function.

var fn = "function a(){}";
var es6fn = "()=>{}";

console.log(eval(fn)); // undefined
console.log(eval(es6fn)); // ()=>{}
console.log(typeof eval(es6fn)); // ()=>{} i.e. a function
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
nivas
  • 3,138
  • 3
  • 16
  • 15
  • the es6 Lamda expression behaves like an anonymous function - so that is one difference between fn and es6fn – jHilscher May 05 '17 at 13:19
  • 1
    As a side note: this is nice and well for toying around but please don't use this in production - your future self will be thankful – mfeineis May 05 '17 at 13:25

4 Answers4

2

Lets take a step back and see what is actually going on here. I think you are misunderstanding the point MDN is trying to make. The only function that is executed in your example is eval. The (...) the documentation is mentioning are not for executing the function inside the string but for changing how the function definition is evaluated.

A function call would function a(){}() but the docs talk about putting the function definition inside parenthesis: (function(){}).


There are basically thee major ways to define functions:

  1. Function declaration

    function foo() {}
    
  2. Function expression

    var foo = function() {}
    
  3. Arrow function

    var foo = () => {}
    

To understand the difference between a function declaration and a function expression, we have to understand the difference between statements and expressions (a declaration is basically like a statement).

A statement is something that has side effects and does not produce a value. if, for, switch, etc are all statements.

An expression is something that produces a value. E.g. 5 is a number literal that produces the value 5. 5 + 3 is an expression that computes the sum of the two literals, i.e. evaluating it will return the value 8.

A function declaration is like a statement. It doesn't produce a value itself, but as a side effect, a variable is defined whose value is a function (you can see in the specification that nothing happens when a function declaration is evaluated (they have already been processed at that point)).

A function expression is very similar, but instead of defining a variable, evaluating it simply results in the function object.

And that is the reason why

eval('function a() {}') // undefined, but a is defined as side effect
eval('(function a() {})') // a function object

produce different results. The first is interpreted as function declaration. A variable a will be created, but no value is created that eval could return. In the second case, the grouping operator ((...)) forces the function definition to be interpreted as a function expression, which means that a value is produced and return by eval.


Now regarding arrow functions: There is no ambiguity here. Arrow function definitions are always expressions, i.e. evaluating them always produces a value.

eval(`() => {}`) // a function object

To sum up

While there is a difference between arrow functions and function declarations/expressions, this difference is not the reason for the results you are seeing with eval. The difference here is because of evaling a statement/declaration and an expression.

Felix Kling
  • 795,719
  • 175
  • 1,089
  • 1,143
  • Thanks, it really helped, i do have one question though, why `eval('function (){}')` produces `Syntax error`, as it is a function expression just like arrow functions. – nivas May 06 '17 at 18:37
  • 1
    It's not a function expression, it's still considered a function declaration, but function declarations need names, hence the error. – Felix Kling May 07 '17 at 00:14
0

In your example, a is declared as it's a named function. In the second case, you just write an expression which is a lambda function. See here and here.

If you want to get the same effect for fn, do

`console.log(eval("var a = function(){}"))`; //`function(){}`.
Kris Ku
  • 1,507
  • 1
  • 16
  • 32
0

First of all, EcmaScript is the "official" name for JavaScript. Now that ES2015 is finalised, it effectively just becomes JavaScript v6 to most people. So, this difference does not come from the different engin.

The origin of the different behavior comes from the result of the string which is written in the eval function. the result of the first eval string is a function definition and there is not anything to return. On the other side, the second eval is evaluating a lambda function, so the result of the eval is that function. To clear this concept, you can rewrite the code like the following:

var fn = "function a(){ return 1;}";
var es6fn = "()=>{}";

console.log(eval(fn)); // undefined
console.log(eval(es6fn)); // ()=>{}
console.log(typeof eval(es6fn)); // ()=>{} i.e. a function
console.log(a()); // call the a() function

As, you can see, the a() is defined as a function, and you can use the function after the first eval. So, the first eval is run and all back to the return value for eval function.

OmG
  • 18,337
  • 10
  • 57
  • 90
0

The documentation says nothing on function execution. The functions won't be executed, unless they are executed explicitly like (() => {})().

The quote

eval as a string defining function requires "(" and ")" as prefix and suffix

refers to interpreting the string as function expression rather than function declaration.

// will throw SyntaxError
// because function declaration requires a name
typeof eval('function (){}'); 

typeof eval('function a(){}') === 'undefined';
typeof eval('(function a(){})') === 'function';
typeof eval('null, function a(){}') === 'function';
typeof eval('()=>{}') === 'function';

Arrow function is always an expression, it doesn't need auxiliary constructions like comma or parentheses to interpret is an expression, here is the difference.

Estus Flask
  • 206,104
  • 70
  • 425
  • 565
  • can you explain how this is `eval('null, function a(){}')` returns a function. I don't know how this treated as a function and their is no mention of this – nivas May 05 '17 at 13:54
  • Comma operator is a known way to force it to be interpreted as expression. See https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Operators/Comma_Operator . `null, function (){}` interprets left-hand expression (it can be anything, null or 0 or 1 for brevity) and returns right-hand expression, i.e. a function. Here's a popular use for this hack, http://stackoverflow.com/questions/9107240/1-evalthis-vs-evalthis-in-javascript – Estus Flask May 05 '17 at 14:14