Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Are closures in javascript recompiled

Let's say we have this code (forget about prototypes for a moment):

function A(){
  var foo = 1;
  this.method = function(){
    return foo;
  }
}
var a = new A();

is the inner function recompiled each time the function A is run? Or is it better (and why) to do it like this:

function method = function(){ return this.foo; }
function A(){
  this.foo = 1;
  this.method = method;
}
var a = new A();

Or are the javascript engines smart enough not to create a new 'method' function every time? Specifically Google's v8 and node.js.

Also, any general recommendations on when to use which technique are welcome. In my specific example, it really suits me to use the first example, but I know thath the outer function will be instantiated many times.

like image 780
disc0dancer Avatar asked May 10 '10 20:05

disc0dancer


3 Answers

From what I understand, it is not so much a matter of "compiling" the function as it is having a different "scope" each time it is executed.

The second method you used will always have method from the same scope.

The first method puts method inside the scope of the A() function call. So any information that is inside that scope (var foo, function parameters, etc) are stored in that instance of the functions scope. So, the same function code will be referenced each time, but it will be in a different scope (and therefore a different "object").

like image 190
gnarf Avatar answered Oct 13 '22 23:10

gnarf


Yes, you are creating a new Function object at each instantiation of an A object. You can demonstrate this as follows:

function A(){
  var foo = 1;
  this.method = function(){
    return foo;
  }
}
var a = new A();
var b = new A();
alert(a.method == b.method); // Returns false; two different Function objects

If you want to reuse the same Function object, make the method a property of the prototype, not the instances.

function B() {
  this.foo = 1;
}

B.prototype.method = function() {
  return this.foo;
}

var a = new B();
var b = new B();
alert(a.method == b.method); // Returns true; it's the same Function object

Edit: As far as I know, there is no reason to do something like the first version except to create private variables in a JavaScript object. In the original example, foo is private. Nothing can access it directly from outside the object. Unfortunately, when you are instantiating a large number of objects using this technique, it can have an impact on performance and memory footprint.

In my code, I use a naming convention to distinguish between "public" and "private" properties. I name private properties with an underscore as the first character. So if I see something like myObject._someMethod(), I know something is wrong.


Edit2: From http://code.google.com/apis/v8/design.html, I would think that V8 compiles the closure once, when it creates the hidden class which contains the method property.

like image 31
jhurshman Avatar answered Oct 13 '22 23:10

jhurshman


The method is not recompiled.

The Javascript interpreter will create a new closure object containing inner methods and local variables every time you call the outer methods.

The exact implementation depends on the Javascript engine.

like image 45
SLaks Avatar answered Oct 13 '22 21:10

SLaks