11

today I've read we have a way of declaring the function by Function constructor. But I never seen the actual implementation that uses Function constructor in real. So I would like to ask, are there any circumstances that we can get benefit by using Function constructor as opposed to using function() declaration? And what are the hidden differences of between?(if there is any)

Function Constructor

var func = new Function("x", "y", "return x*y;"); // pass the context by String

function():

var func = function(x, y){ return x*y; }

Thanks

Justin Johnson
  • 30,978
  • 7
  • 65
  • 89
c4il
  • 965
  • 3
  • 16
  • 27

4 Answers4

10

The Function constructor is a form of eval, which should generally be avoided (it's slow and considered insecure). There is really no benefit to using the Function constructor over the built in function statement unless you want to construct a function from dynamic components, which is pretty rare. There are legitimate uses for this form, however most of the time it's used unnecessarily which is why it's looked down upon and generally avoided.

Also, functions created with the function constructor will not keep a reference to the environment they were defined in (the closure). When executed, they will pull those variables directly from the global scope.

var f, a;
(function () {
   var a = 123;
   f = new Function("return a");
})();

f(); //undefined

a = "global"
f(); // "global"

Whereas regular functions do keep a reference to the environment in which they were defined:

var f;
(function () {
   var a = 123;
   f = function () { return a; }
})();
f(); //123
Scb
  • 339
  • 1
  • 5
  • 19
Cristian Sanchez
  • 31,171
  • 11
  • 57
  • 63
  • I am wondering what they were thinking when building this `Function` object. – Tarik Sep 26 '10 at 18:56
  • Well it's pretty useful for something like the js1k competition :-) – Pointy Sep 26 '10 at 19:06
  • 6
    @Daniel, Note that the "slow" part would be only the function *compilation*, after a function object is constructed, it will behave exactly the same as if it was created with a `FunctionDeclaration` or a `FunctionExpression`. – Christian C. Salvadó Sep 26 '10 at 19:11
  • @CMS: Yes, of course. But since we're on the topic of the constructor I thought it would be a good idea to include the possible performance implications of using the constructor method. This highly unscientific test shows that the difference is non-negligible: http://jsperf.com/function-constructor-vs-function-literal Though I admit that in the grand scheme of things it probably won't be noticed by the user. – Cristian Sanchez Sep 26 '10 at 19:32
  • 3
    That only tests the difference in defining the function, not running it. That is the whole point. Dynamically constructing a function can improve performance by removing unneeded conditional checks, loop unrolling, etc. The cases where such fine tuning is needed are rare but they do exist. Also there is something to be said for creating a function that does not capture a bunch of unneeded variables in a closure. – MooGoo Sep 26 '10 at 20:42
  • 2
    @MooGoo: Yes... that was the intention of the test. It has been established that there is no difference in execution times. This question is concerned with the different methods of *declaring* a function. – Cristian Sanchez Sep 26 '10 at 20:56
  • 2
    I don't think the differences in performance regarding defining a function was ever in doubt. I just feel it is important to stress that `new Function != eval` when it comes to speed. Continually redefining a function in a loop with the `Function` constructor to test for its performance is no different than just using `eval` directly, but it is misleading because that is *never* how the Function constructor would be used. – MooGoo Sep 27 '10 at 01:25
2

Well, the obvious difference when working with strings is that you have the option of meta-programming, by constructing the string at runtime (the same as you could with eval). However, this is double edged, and arguably leads into a range of other problems with literal concatenation (injection), and perhaps simply complexity. If you don't need the string version, I wouldn't use it to be honest.

A side benefit of the regular (non-string) version is that most javascript minifiers (or obfuscators) will know what to do with it. This seems unlikely for the string, i.e. they'll leave it "as is" (not minified or obfuscated).

Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
  • 1
    @Braveyard - done *right* meta programming is fine; but it is also a great way to open up xss holes if done wrong. For example, if the user can abuse the string to get other users to post their cookies to you. – Marc Gravell Sep 26 '10 at 20:09
2

If you're writing a Javascript parser and are interpreting a string as a function then you could use a function constructor. EG if you are given:

"function(x){return x+2}"

And you have some sort of lexical parser and it finds that substring is indeed a function, to translate it into a real function you would use new Function and add it to your tree.

Otherwise there really isn't much of a use that I can think of.

meder omuraliev
  • 183,342
  • 71
  • 393
  • 434
0

Additional notes to Cristian Sanchez' posting.

You can never access local scope vars within a 'Function'-Evaluation.

Lets see the difference between Function and eval.

Function-Example:

var f, a = 1;
(function () {
    var a = 123;
    f = new Function("return a");
})();
console.log(f()) // 1

The Function-Constructor doesn't know anything about the local scope, because it creates a new isolated Scope underneath the window/global-Object - not at the position where it is - that is the main-difference to eval.

Eval-Example:

var f, a = 1;
(function () {
    var a = 123;
    eval("f = function() { return a }");
})();
console.log(f()) // 123

'eval' has access to the local vars. Even if you scope the whole thing.

var f, a = 1;
(function () {
    var a = 123;
    eval("f = (function() { function f() { return a }; return f; })();");
})();
console.log(f()) // still 123

In the following example f() throws an error - "a" is undefined in his own (and global) scope. The Function-Constructor has its own special scope without knowing anything outside - except his parent scope - the window/global-object.

delete a;
var f;
(function () 
{ 
    var a = 1;
    f = new Function("return a");
})();

console.log(f());  // Throws error (a is not defined)

If you want to use local vars, pass it as parameters to the Function-Constructor inside the inner scope!

var f, a = 1;
(function () { 
    var a = 123; 
    f = new Function("a", "return a");

    console.log(f(a)); // passing inner a: result = 123
})();

console.log(f(a)); // passing outer a: result = 1

or

var result, a = 1;
(function () { 
    var a = 123; 
    var f = new Function("a", "return a");
    result = f(a); // store result in global var
})();

console.log(result); // 123

You can execute Function directly with call/apply, too (no "new" needed).

Function('a','b','c', 'console.log(c,b,a)').call(this, 1, 2, 3); // output: 3 2 1
Function('console.log(arguments)').apply(this, [1, 2, 3]); // access through arguments[0-3]

By the way, it's always recommend, setting the strict mode, to enable correct ES5 behaviour.

With strict-mode 'this' is (correctly) undefined by default - until you bind an object.

Function('console.log(this)')(); // this is 'window' in sloppy mode
Function('"use strict"; console.log(this)')(); // this is undefined - correct behavior

If you want, you can bind 'this' explicitly

// bind 'this' to 'window' again
Function('"use strict";console.log(this)').bind(window)();
// bind 'this' to an Object without __proto__
Function('"use strict";console.log(this)').bind(Object.create(null))(); 

Of course you can bind any function/class-object to extend objects.

function SomeClass() 
{
    this.a = 1;
}

var cls = new SomeClass();

new Function('"use strict"; this.a = 5; this.b = 6;').bind(cls)();

console.log(cls.a); // a = 5 - override property
console.log(cls.b); // b = 6 - appended property

Same result with direct call, without 'new' keyword.

function SomeClass() 
{
    this.a = 1;
}

var cls = new SomeClass();

Function('"use strict"; this.a = 5; this.b = 6; this.foo = function(){console.log("bar")}').call(cls);

console.log(cls.a); // a = 5 - override property
console.log(cls.b); // b = 6 - appended property
console.log(cls.foo()); // bar - appended function

Every function/class is created through the the 'Function'-constructor.

So you don't have to write "Function" in your code. You can use the constructor-object, too.

function SomeClass() 
{
    this.a = 1;
}

var cls = new SomeClass();

SomeClass.constructor("this.a = 2;").call(cls);

cls; // SomeClass {a: 2}, because "SomeClass.constructor" === Function

The use of 'Function' is good for example for games, if you have a XMLHttpRequest-Preloader, which loads a very large Javascript-File (5-10 MB bundled scripts), while you want display a loading-bar or something else to the user, instead loading the whole thing with a script-tag, while the user is waiting for page-loading without any visual response.

It does not matter if you load a large script via a script tag, or via Function once on startup. The engine has to load the plain code and evaluate it either way. There are no security aspects, if your(!) code came from a trusted source (your domain) and you know whats inside.

'Function' and 'eval' are only bad with untrusted code (when other users have influence on it) or in loops (slow performance due compiling), but it is totally okay to load & evaluate your own scripts on startup, if the code is the same as in external Javascript-files.

SammieFox
  • 554
  • 1
  • 6
  • 4