Are closures in javascript recompiled
Let's say we have t开发者_StackOverflow中文版his 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.
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").
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.
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.
I would guess it gets compiled only once... because the "this" keyword refer to the execution context... so the compiler doesn't need to know much about a function to interpret it.
Furthermore, when you declare a variable in the bottom of a function, it is still accessible at the top:
function test()
{
alert(hello);
// ...
var hello = 2;
}
It is the same thing with functions. I would believe with those 2 things in mind, that it doesn't get re-compiled every time a A gets called.
Mike
Imagine a function as just another object, and then when you create a new one, it's just a copy of the old one, with some data variable changed. You don't need to re-parse the object's source for that to happen. A good analogy is functionoids in C++, function objects in Lua, and I don't really know many other languages.
function A(){
var foo = 1;
this.method = function(){
return foo;
}
}
can't be compiled into
function method = function(){ return this.foo; }
function A(){
this.foo = 1;
this.method = method;
}
because the functionality would change. The first example has a variable 'foo' that is only visible to the constructor 'A' and to the function called 'method' whereas in the second example the accessible to everything that has access to the instance of 'A'.
It is possible to compile it into
function method = function(){ return 1; }
function A(){
this.method = method;
}
But I don't think that any javascript engine out there will go that far, but if you are able to preprocess your files and willing to put in an extra bit of effort, the google closure compiler could go pretty far if it's used in advanced mode.
精彩评论