// Case A
function Constructor() {
this.foo = function() {
...
};
...
}
// vs
// Case B
function Constructor() {
...
};
Constructor.prototype.foo = function() {
...
}
人们建议使用原型的一个主要原因是.foo
在原型的情况下创建一次,其中当使用另一种方法时多次创建this.foo
。
然而,人们会期望口译员可以优化这一点。因此,在案例A中只有一个函数foo
的副本。
当然,由于闭包,每个对象仍然有一个唯一的作用域上下文,但是每个对象的新函数开销较少。
现代JS解释器是否优化了案例A,因此只有一个函数foo
的副本?
答案 0 :(得分:8)
是的,创建函数会占用更多内存。
......而且,不,解释员不会将案例A优化为单一函数。
原因是the JS scope chain要求函数的每个实例捕获创建它时可用的变量。也就是说,modern interpreters关于案例A的better比以前更avoid unnecessary closures,但很大程度上是因为封闭函数的表现是几年前的一个已知问题。
由于这个原因,Mozilla对this test说,但是闭包是JS开发人员工具包中最强大和最常用的工具之一。 更新:使用node.js(即V8,Chrome中的JS解释器)运行{{3}},创建构建器的1M'实例'。使用caseA = true
我得到了这个内存使用情况:
{ rss: 212291584,
vsize: 3279040512,
heapTotal: 203424416,
heapUsed: 180715856 }
使用caseA = false
我得到了这个内存使用情况:
{ rss: 73535488,
vsize: 3149352960,
heapTotal: 74908960,
heapUsed: 56308008 }
因此闭包函数肯定会消耗更多的内存,几乎是3倍。但从绝对意义上讲,我们只讨论每个实例约140-150字节的差异。 (但是,根据创建函数时的范围内变量的数量,这可能会增加。)
答案 1 :(得分:2)
我相信,在节点中进行了一些简短的测试之后,在案例A和B中,内存中只有一个函数foo
的实际代码副本。
案例A - 为每次执行存储对函数代码及其当前执行范围的引用的Constructor()
创建了一个函数对象。
案例B - 只有一个范围,一个功能对象,通过原型共享。
答案 2 :(得分:0)
javascript解释器也没有优化原型对象。它只是每种类型中只有一个(多个实例引用)的情况。另一方面,构造函数创建新实例及其中定义的方法。因此,根据定义,这实际上不是解释器“优化”的问题,而是简单地理解正在发生的事情。
另一方面,如果解释器尝试合并实例方法,如果您决定在特定实例中更改一个值,则会遇到问题(我希望不会将头痛添加到语言中) :)