关于 JavaScript 中闭包/封装效率的问题
Posted
技术标签:
【中文标题】关于 JavaScript 中闭包/封装效率的问题【英文标题】:Question about the efficiency of closure/encapsulation in JavaScript 【发布时间】:2011-09-13 23:00:08 【问题描述】:我对 javascript 有点陌生,如果这是一个愚蠢的问题,请耐心等待。
假设我有一个看起来像这样的“类”:
var obj = function ()
var val;
return
setVal: function(newVal)
val = newVal;
,
getVal: function()
return val;
;
;
假设我的语法是正确的,这定义了一个具有名为“value”的“私有”属性的类,以及设置/获取该属性的方法。现在,我将从这个类创建两个对象:
var myObj = obj();
var yourObj = obj();
这会为 each 对象创建单独的 setVal() 和 getVal() 方法吗?如果不是,为什么不呢?如果是这样,在构建高效的 Web 应用程序时,这是一个严重的问题吗?在大多数/所有情况下,关闭效率的权衡(如果有的话)是否值得?我是笨蛋吗?
谢谢, 杰拉德
【问题讨论】:
这是一篇关于闭包和原型设计的好文章。 ruzee.com/blog/2008/12/… 如果您刚开始使用 javascript,这是一个很好的问题。 【参考方案1】:var obj = function ()
var val;
return
setVal: function(newVal)
val = newVal;
,
getVal: function()
return val;
;
;
这个函数的作用如下:
创建名为val
的变量
创建新对象
创建一个新函数并将其分配给字段setVal
创建一个新函数并将其分配给字段getVal
返回对象。
所以你总是在创造 4 个新事物。
如果页面上的对象少于 1000 个,这不是问题。重构它是一种微优化。
替代方法是不依赖局部变量并使用this._val
表示val
是私有的。
【讨论】:
【参考方案2】:它确实在概念上这样做。然而,由于这是一种常见的模式,现代 JavaScript JITers 知道如何优化它,以便在内存中只存储一个代码副本,并通过适当的指针重定向使其与相关闭包一起工作。
编辑:虽然我不太愿意深入研究源代码,但这里有一些基本证明。 Download the Chrome dev channel release,并在运行以下代码之前和之后拍摄堆快照:
var obj = /* as above */;
var objs = [];
for (var i = 0; i < 10000; ++i)
objs.push(obj());
然后对这段代码做同样的事情:
function Obj()
Obj.prototype.setVal = function (value) this._val = value; ;
Obj.prototype.getVal = function () return this._val; ;
var objs = [];
for (var i = 0; i < 10000; ++i)
objs.push(new Obj());
您会发现堆快照在两种情况下都显示相同的“代码”数字,因此我描述的优化确实正在执行。
【讨论】:
它仍然创建了两个方法实例setVal
和getVal
是的,在 JavaScript 中确实如此。但是不会降低效率,因为在现代 JIT 编译器所编译到的机器代码级别上,每个都只有一个实例。
请用指向 V8 和 Jaegermonkey 源代码的链接来备份它。我想所有这些函数都有多个实例,每个实例都有指向正确闭包上下文的指针。如果实际上只有两个功能,那么作为优化真的很令人印象深刻
-1 这种优化不仅是不可能的(每个闭包都是一个单独的状态,并且需要保存在内存中的某个地方),而且您可以清楚地看到闭包方法中的javascript内存使用量飙升vs 原型方法。每次调用 +3MB,而每次调用原型几乎没有。以上是关于关于 JavaScript 中闭包/封装效率的问题的主要内容,如果未能解决你的问题,请参考以下文章