是否重新编译了javascript中的闭包

时间:2010-05-10 20:42:46

标签: javascript performance closures

假设我们有这个代码(暂时忘记原型):

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

是每次运行函数A时重新编译的内部函数吗?或者更好(以及为什么)这样做:

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

或者javascript引擎足够智能,不会每次都创建一个新的'方法'功能?特别是谷歌的v8和node.js。

此外,欢迎任何关于何时使用哪种技术的一般性建议。在我的具体示例中,使用第一个示例非常适合我,但我知道外部函数将被多次实例化。

6 个答案:

答案 0 :(得分:7)

据我所知,这不是“编译”函数的问题,因为每次执行时它都有不同的“范围”。

您使用的第二种方法始终具有来自同一范围的method

第一种方法将method置于A()函数调用的范围内。因此,该范围内的任何信息(var foo,函数参数等)都存储在函数范围的那个实例中。因此,每次都会引用相同的函数代码,但它将在不同的范围内(因此是不同的“对象”)。

答案 1 :(得分:3)

是的,您正在A对象的每个实例化中创建一个新的Function对象。您可以按如下方式证明:

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

如果要重用相同的Function对象,请将该方法设为原型的属性,而不是实例。

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

编辑:据我所知,除了在JavaScript对象中创建私有变量之外,没有理由像第一个版本那样做。在原始示例中,foo是私有的。没有什么可以直接从对象外部访问它。不幸的是,当您使用这种技术实例化大量对象时,它会对性能和内存占用产生影响。

在我的代码中,我使用命名约定来区分“公共”和“私有”属性。我将私人属性命名为下划线作为第一个字符。所以,如果我看到像myObject._someMethod()这样的东西,我就知道出了什么问题。


Edit2:从http://code.google.com/apis/v8/design.html开始,我认为V8会在创建包含method属性的隐藏类时编译闭包一次。

答案 2 :(得分:2)

不重新编译该方法。

每次调用外部方法时,Javascript解释器都会创建一个包含内部方法和局部变量的新闭包对象。

确切的实现取决于Javascript引擎。

答案 3 :(得分:0)

我猜它只会被编译一次...因为“this”关键字指的是执行上下文...所以编译器不需要太多了解一个函数来解释它。

此外,当您在函数的底部声明一个变量时,它仍然可以在顶部访问:

function test()
{
  alert(hello);
  // ...
  var hello = 2;
}

功能与此相同。我会相信这两件事,每次调用A时都不会重新编译。

麦克

答案 4 :(得分:0)

将一个函数想象成另一个对象,然后在创建一个新对象时,它只是旧函数的副本,其中一些数据变量已更改。您无需重新解析对象的源代码即可。一个很好的比喻是C ++中的functionoids,Lua中的函数对象,我真的不知道很多其他语言。

答案 5 :(得分:0)

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

无法编译成

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

因为功能会改变。第一个例子有一个变量'foo',它只对构造函数'A'和名为'method'的函数可见,而在第二个例子中,可访问所有有权访问'A'实例的函数。

可以将其编译成

function method = function(){ return 1; }
function A(){ 
  this.method = method;
}

但是我不认为那里的任何javascript引擎会走得那么远,但是如果你能够预处理你的文件并愿意付出额外的努力,那么google closure compiler可能会走得很远如果它在高级模式下使用。