【问题标题】:Question about the efficiency of closure/encapsulation in JavaScript关于 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,这是一个很好的问题。

标签: javascript oop performance closures


【解决方案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());
    }
    

    您会发现堆快照在两种情况下都显示相同的“代码”数字,因此我描述的优化确实正在执行。

    【讨论】:

    • 它仍然创建了两个方法实例setValgetVal
    • 是的,在 JavaScript 中确实如此。但是不会降低效率,因为在现代 JIT 编译器所编译到的机器代码级别上,每个都只有一个实例。
    • 请用指向 V8 和 Jaegermonkey 源代码的链接来备份它。我想所有这些函数都有多个实例,每个实例都有指向正确闭包上下文的指针。如果实际上只有两个功能,那么作为优化真的很令人印象深刻
    • -1 这种优化不仅是不可能的(每个闭包都是一个单独的状态,并且需要保存在内存中的某个地方),而且您可以清楚地看到闭包方法中的javascript内存使用量飙升vs 原型方法。每次调用 +3MB,而每次调用原型几乎没有。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-05-08
    • 2012-02-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多