110

Are these two functions doing the same thing behind the scenes? (in single statement functions)

var evaluate = function(string) {
    return eval('(' + string + ')');
}

var func = function(string) {
    return (new Function( 'return (' + string + ')' )());
}

console.log(evaluate('2 + 1'));
console.log(func('2 + 1'));
qwertymk
  • 34,200
  • 28
  • 121
  • 184
  • 3
    In fact this is used in jQuery 1.7.2 line 573. Though with "some security checks" – PicoCreator May 05 '12 at 19:18
  • 2
    Why is `new` considered in this discussion? `Function` implicitly instantiates a `function object`. Excluding `new` will not change the code at all. Here is a jsfiddle demonstrating that: http://jsfiddle.net/PcfG8/ – Travis J Apr 05 '13 at 21:55

6 Answers6

142

No, they are not the same.

  • eval() evaluates a string as a JavaScript expression within the current execution scope and can access local variables.
  • new Function() parses the JavaScript code stored in a string into a function object, which can then be called. It cannot access local variables because the code runs in a separate scope.

Consider this code:

function test1() {
    var a = 11;
    eval('(a = 22)');
    alert(a);            // alerts 22
}

If new Function('return (a = 22);')() were used, the local variable a would retain its value. Nevertheless, some JavaScript programmers such as Douglas Crockford believe that neither should be used unless absolutely necessary, and evaling/using the Function constructor on untrusted data is insecure and unwise.

Community
  • 1
  • 1
PleaseStand
  • 31,641
  • 6
  • 68
  • 95
  • 18
    "should never be used" is such a broad statement. How about, should never be used when any of the input is out of your control. Having said that, I never needed to use it, except for parsing JSON. But I have answered questions here that seemed like valid uses, it involved something like allowing admins to generate templating functions that a end-users could use. In this case the input was generated by an admin, so it was acceptable – Ruan Mendes Jan 05 '11 at 01:25
  • 4
    @Juan: Crockford's point is that eval is often misused (depends on your perspective), so it should be excluded from a "best practices" JavaScript. I do agree, however, that it is useful for such uses as JSON or arithmetic expression parsing when input is first properly validated. Even Crockford uses it in his JSON library json2.js. – PleaseStand Jan 05 '11 at 01:50
  • 1
    So does this mean that `new Function(code)` is the same as `eval('(function(){'+code+'})()')` or is it an entirely new execution context? – George Mauer Jul 07 '12 at 17:21
  • 8
    @GeorgeMauer: I think you mean `eval('(function(){'+code+'})')`, which would return a function object. [According to MDN](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function), "Functions created with the Function constructor do not create closures to their creation contexts; they always run in the window context (unless the function body starts with a "use strict"; statement, in which case the context is undefined)." – PleaseStand Jul 07 '12 at 19:24
7

No.

In your update, the calls to evaluate and func produce the same result. But, they are most definitely not "doing the same thing behind the scenes". The func function creates a new function, but then immediately executes it, whereas the evaluate function simply executes the code on the spot.

From the original question:

var evaluate = function(string) {
    return eval(string);
}
var func = function(string) {
    return (new Function( 'return (' + string + ')' )());
}

These will give you very different results:

evaluate('0) + (4');
func('0) + (4');
palswim
  • 11,856
  • 6
  • 53
  • 77
6

new Function creates a function that can be reused. eval just executes the given string and returns the result of the last statement. Your question is misguided as you attempted to create a wrapper function that uses Function to emulate an eval.

Is it true that they share some code behind the curtains? Yes, very likely. Exactly the same code? No, certainly.

For fun, here's my own imperfect implementation using eval to create a function. Hope it sheds some light into the difference!

function makeFunction() {
  var params = [];
  for (var i = 0; i < arguments.length -  1; i++) {
    params.push(arguments[i]);
  }
  var code = arguments[arguments.length -  1];


 // Creates the anonymous function to be returned
 // The following line doesn't work in IE
 // return eval('(function (' + params.join(',')+ '){' + code + '})');
 // This does though
 return eval('[function (' + params.join(',')+ '){' + code + '}][0]');
}

The biggest difference between this and new Function is that Function is not lexically scoped. So it wouldn't have access to closure variables and mine would.

Ruan Mendes
  • 90,375
  • 31
  • 153
  • 217
  • 1
    why not use `arguments.slice()` instead of the for loop? Or if arguments is not a true array, `[].slice.call(arguments, 1)`. – Xeoncross Jul 21 '14 at 18:40
3

Just want to point out some syntax used in the examples here and what it means:

 var func = function(string) {
     return (new Function( 'return (' + string + ')' )());
 }

notice that the Function(...)() has the "()" at the end. This syntax will cause func to execute the new function and return the string not a function that returns string, but if you use the following:

 var func = function(string) {
     return (new Function( 'return (' + string + ')' ));
 }

Now func will return a function that returns a string.

Jack D Menendez
  • 154
  • 1
  • 7
2

If you mean, will it yield the same results, then yes... but just to eval (aka, "evaluate this string of JavaScript") would be much simpler.

EDIT Below:

It's like saying... are these two math problems the same:

1 + 1

1 + 1 + 1 - 1 + 1 - 1 * 1 / 1

Timothy Khouri
  • 31,315
  • 21
  • 88
  • 128
1

In that example, the results are the same, yes. Both execute the expression you pass. This is what makes them so dangerous.

But they do different things behind the scense. The one involving new Function(), behind-the-scenes, creates an anonymous function from the code you supply, which is executed when the function is invoked.

The JavaScript you pass to it is technically not executed until you invoke the anonymous function. This is in contrast to eval() which executes the code right away, and doesn't generate a function based on it.

Chris Laplante
  • 29,338
  • 17
  • 103
  • 134
  • Can you expound a little more? Aren't they both executed in the return statement? Does the Function() one use another stack call level than eval? – qwertymk Jan 05 '11 at 00:49
  • `Does the Function() one use another stack call level than eval?`: I would assume so, because `eval()` doesn't create a function from your input- it just executes it. `new Function()` creates a new function, which it then invokes. – Chris Laplante Jan 05 '11 at 00:50
  • @SimpleCoder: Function() doesn't add anything to the call stack. Only if you call the resulting function. eval does the exact same thing (if applied in the context of the question) – Ruan Mendes Sep 23 '11 at 18:28