假设我们有这个代码(暂时忘记原型):
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。
此外,欢迎任何关于何时使用哪种技术的一般性建议。在我的具体示例中,使用第一个示例非常适合我,但我知道外部函数将被多次实例化。
答案 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可能会走得很远如果它在高级模式下使用。