【问题标题】:Is crockford's JavaScript constructor pattern really supposed to be faster?克罗克福德的 JavaScript 构造函数模式真的应该更快吗?
【发布时间】:2013-01-02 16:17:15
【问题描述】:

我最近尝试为经常创建的值对象优化一些代码。 (一个三维向量,fwiw)

我尝试的一件事是将构造函数从匿名方法工厂模式转换为普通的 JavaScript 构造函数。

这导致了 severe performance penalty 让我感到惊讶,因为在我的 last question 关于 JavaScript 构造函数/工厂模式的主题中非常推荐使用“新”和普通构造函数。

很可能是我的测试过于简单,或者完全是错误的,或者是最近在 chrome 的 JavaScript 引擎中进行的性能优化的结果,或者以上所有原因。无论如何,我真的很想知道为什么我的“优化”会导致性能下降——最重要的是:我的 jsperf 测试运行是否有任何明显的问题?

【问题讨论】:

  • 克罗克福德对我来说是最快的 ~50%
  • @Zaz: 2 件事...1) 克罗克福德是否声称他的方法更快?我认为这只是它避免了全局变量,因此“更安全”。 2) 你确定你展示的东西是 Crockford 推荐的吗?我在考虑更多关于此页面上最后一个示例的内容...javascript.crockford.com/prototypal.html...if 我错了(可能)你能把我链接到你从哪里得到这个,因为我目前正在重读“The好零件”
  • 您正在比较两件不做同样事情的事情,这两者都不是 Crockford 的对象构造函数。
  • @Mathletics:没有理由比较两个相同的代码位。除了已经提到的构造性能差异之外,所介绍的两种技术之间存在哪些行为或性能差异?
  • @ScottSauyet 这个问题表明他正在测试 Crockford 的构造函数;比较直接设置prototype 与使用new 关键字。创建对象的两种方法,但肯定不是“相同的代码位”。整个问题都是关于施工性能的,但提供的测试并不能代表我认为 OP 认为他在问的问题。

标签: javascript performance constructor


【解决方案1】:

您的测试之间的主要区别是:

  • {} is way faster than new Object,这表明new 比使用{} 慢。 ([]new Array 也是如此。)

  • 您的测试产生不同的结果:make 工厂函数的结果不是Make 对象。构造的Make 有一个原型,由所有Make 对象共享。您的工厂函数的结果只是一个裸Object,并且在其原型链中有一个原型(Object.prototype),而Make 构造的对象有两个(Make.prototype,然后是Object.prototype)。

    我使用非标准的__proto__ 属性创建了一个fork of your test,它带有一个实际返回Make 对象(而不是简单的Object)的工厂函数,它比使用a 慢得多构造函数。 IE 不支持__proto__,但 Firefox 和 Chrome 的结果看起来相当确定。

【讨论】:

  • 我喜欢斯科特的回答和你的回答。我认为你的更清楚,尤其是关于ObjectMake 的观点。谢谢!
【解决方案2】:

构造函数优化的一件事是共享属性,通常是方法。如果多个对象使用与方法相同的函数,或者共享其他命名属性,那么对原型的一个赋值将在从构造函数创建的所有对象之间共享该属性的单个实例,从而减少内存开销,并且不需要重复为创建的每个对象分配每个此类属性,从而减少构建时间开销。

由于您的样本不包含任何此类属性,因此您不会看到此类好处。但是,如果您的生产代码不包含构造对象的共享属性,则很可能没有理由切换到构造函数。

因此,例如,如果您有代码 like this:

function make(p) {
    return {
        parm: p,
        addTwo: function() {return this.parm + 2;},
        double: function() {return this.parm * 2;},
        square: function() {return this.parm * this.parm;}
    };
};

它可能会运行得比这更慢:

function Make(p) {
    this.parm = p;
}
Make.prototype.addTwo = function() {return this.parm + 2;};
Make.prototype.double = function() {return this.parm * 2;}
Make.prototype.square = function() {return this.parm * this.parm;}

如果创建多个实例,也会占用更多内存。

【讨论】:

  • 所以我的问题是,虽然我的原始模式很糟糕,但我的“优化”并没有更好。我重构了向量类,按照您的建议将原型用于其功能,并且我的代码速度提高了八倍。谢谢您的帮助。 :)
  • 很高兴听到这个消息。不太清楚为什么人们对答案投了反对票。这不是用于创建此类对象的唯一模式。您可能会调查Object.create(),它在大多数现代 JS 引擎中都可用,并且可以在其他引擎中用于这些用途。它可能被广泛认为是更现代的解决方案,但具有与此类似的性能特征。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-02-11
  • 2017-06-07
相关资源
最近更新 更多