创建函数会消耗更多内存吗
// Case A
function Constructor() {
this.foo = function() {
...
};
...
}
// vs
// Case B
function Constructor() {
...
};
Constructor.prototype.foo = function() {
...
}
人们建议使用原型的主要原因之一是,在原型的情况下 .foo
创建一次,而在使用原型时 this.foo
创建多次其他方法。
然而,人们期望解释器可以优化这一点。因此,在情况 A 中,只有一个函数 foo
的副本。
当然,由于闭包,每个对象仍然拥有唯一的作用域上下文,但与每个对象的新函数相比,开销更少。
现代 JS 解释器是否优化了案例 A,使得函数 foo
只有一份副本?
// Case A
function Constructor() {
this.foo = function() {
...
};
...
}
// vs
// Case B
function Constructor() {
...
};
Constructor.prototype.foo = function() {
...
}
One of the main reasons people advise the use of prototypes is that .foo
is created once in the case of the prototype where as this.foo
is created multiple times when using the other approach.
However one would expect interpreters can optimize this. So that there is only one copy of the function foo
in case A.
Of course you would still have a unique scope context for each object because of closures but that has less overhead then a new function for each object.
Do modern JS interpreters optimise Case A so there is only one copy of the function foo
?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
是的,创建函数会占用更多内存。
...并且,不,解释器不会将案例 A 优化为单个函数。
原因是 JS 作用域链 要求函数的每个实例捕获其可用的变量它被创建的时间。也就是说,现代解释器是案例 A 比以前更好了,但很大程度上是因为闭包函数的性能几年来是一个已知问题以前。
Mozilla 表示,出于这个原因,要避免不必要的关闭,但关闭只是其中之一JS 开发人员工具包中最强大且最常用的工具之一。
更新:刚刚运行此测试,使用节点创建 1M 个构造函数“实例” .js(即 V8,Chrome 中的 JS 解释器)。使用
caseA = true
我得到了这样的内存使用情况:使用
caseA = false
我得到了这样的内存使用情况:因此,闭包函数肯定会消耗更多的内存,几乎增加了 3 倍。但从绝对意义上来说,我们只讨论每个实例约 140-150 字节的差异。 (但是,这可能会增加,具体取决于创建函数时拥有的范围内变量的数量)。
Yes, creating functions uses more memory.
... and, no, interpreters don't optimize Case A down to a single function.
The reason is the JS scope chain requires each instance of a function to capture the variables available to it at the time it's created. That said, modern interpreters are better about Case A than they used to be, but largely because the performance of closure functions was a known issue a couple years ago.
Mozilla says to avoid unnecessary closures for this reason, but closures are one of the most powerful and often used tools in a JS developer's toolkit.
Update: Just ran this test that creates 1M 'instances' of Constructor, using node.js (which is V8, the JS interpreter in Chrome). With
caseA = true
I get this memory usage:And with
caseA = false
I get this memory usage:So the closure functions are definitely consuming significantly more memory, by almost 3X. But in the absolute sense, we're only talking about a difference of ~140-150 bytes per instance. (However that will likely increase depending on the number of in-scope variables you have when the function is created).
我相信,在 Node 中进行一些简短的测试后,在情况 A 和 B 中,内存中都只有一份函数
foo
的实际代码副本。情况 A - 为每次执行
Constructor()
创建一个函数对象,存储对函数代码的引用及其当前执行范围。情况 B - 只有一个作用域、一个函数对象,通过原型共享。
I believe, after some brief testing in node, that in both Case A and B there is only one copy of the actual code for the function
foo
in memory.Case A - there is a function object created for each execution of the
Constructor()
storing a reference to the functions code, and its current execution scope.Case B - there is only one scope, one function object, shared via prototype.
JavaScript 解释器也没有优化原型对象。它只是每种类型只有一个的情况(多个实例引用)。另一方面,构造函数创建新实例以及其中定义的方法。因此,根据定义,这实际上不是解释器“优化”的问题,而是简单地理解正在发生的事情的问题。
附带说明一下,如果解释器要尝试合并实例方法,那么如果您决定更改特定实例中方法的值,您将会遇到问题(我希望不要将这种头痛添加到语言中):)
The javascript interpreters aren't optimizing prototype objects either. Its merely a case of there only being one of them per type (that multiple instances reference). Constructors, on the other hand, create new instances and the methods defined within them. So by definition, this really isn't an issue of interpreter 'optimization' but of simply understanding what's taking place.
On a side note, if the interpreter were to try and consolidate instance methods you would run into issues if you ever decided to change the value of one in a particular instance (I would prefer that headache not be added to the language) :)