【问题标题】:Javascript prototype operator performance: saves memory, but is it faster?Javascript原型操作符性能:节省内存,但更快吗?
【发布时间】:2011-03-30 10:13:13
【问题描述】:

我阅读了here (Douglas Crockford) 使用原型运算符向 Javascript 类添加方法也节省了内存

然后我读到this John Resig's article “用一堆原型属性实例化一个函数非常、非常、快速,但他是在谈论在标准的方式,还是他在他的文章中谈论他的具体例子?

例如,正在创建这个对象:

function Class1()
{
   this.showMsg = function(string) { alert(string); }
}
var c = new Class1();
c.showMsg();

创建这个对象慢吗?

function Class1() {}
Class1.prototype.showMsg = function(string) { alert(string); }
var c = new Class1();
c.showMsg();

附:

我知道原型用于创建继承和单例对象等。但是这个问题与这些主题没有任何关系。


编辑:可能对 JS 对象和 JS 静态对象之间的性能比较感兴趣的人可以阅读this answer below静态对象肯定更快,显然它们只能在您不需要多个对象实例时使用。

【问题讨论】:

  • 通过添加属性自定义对象就像处理该对象的特殊情况。它占用更多内存并且速度较慢,使用原型明确告诉“编译器”指向类定义,共享相同的内存空间。返回显式对象而不是从方法构建它也可以帮助运行时编译器优化代码(但这并不总是可能的)。 More to read here 来自幻灯片 7
  • Javascript 没有类...
  • @AndreasBergström:Class1 只是一个名称,而不是关键字。
  • @MarcoDemaio 我知道,当我看到人们谈论 JS 中的类时,我的眼睛很痛。

标签: javascript performance function-prototypes


【解决方案1】:

我确信就实例化对象而言,它的速度更快并且消耗的内存也更少,这一点毫无疑问,但我认为 javascript 引擎需要遍历对象的所有属性来确定如果调用的属性/方法是该对象的一部分,如果不是,则检查原型。我不是 100% 确定这一点,但我假设它是这样工作的,如果是这样,那么在某些情况下,你的对象添加了很多方法,只实例化一次并大量使用,那么它可能是一个慢一点,但这只是我没有测试过任何东西的假设。

但最后,我还是同意作为一般规则,使用原型会更快。

【讨论】:

  • 在原型中访问属性会有一些开销,但是大多数引擎使用哈希表,所以添加很多属性并不重要。我认为 IE 是个例外,确实需要遍历每个属性。
  • 是的,当我写这篇文章的时候,我认为多年来必须进行一些优化......所以我想事实上这增加了向对象添加方法/属性的事实是否需要重新构建/更新地图/表格?
  • 是的,添加大量属性最终会导致表重建。
【解决方案2】:

2021 年编辑:

这个问题是在 2010 年提出的,当时 class 在 JS 中不可用。如今,class 已经优化得如此之多,没有理由不使用它。如果您需要使用new,请使用class。但早在 2010 年,当将方法绑定到其对象构造函数时,您有两种选择——一种是使用 this 在函数构造函数内绑定函数,另一种是使用 prototype 在构造函数外部绑定它们。 @MarcoDemaio 的问题有非常简洁的例子。当class 被添加到 JS 中时,早期的实现在性能上接近,但通常更慢。这不再是真的了。只需使用class。我想今天没有理由使用prototype


这是一个有趣的问题,所以我进行了一些非常简单的测试(我应该重新启动浏览器以清除内存,但我没有;把它当作它的价值)。看起来至少在 Safari 和 Firefox 上,prototype 运行速度明显更快[编辑:不是前面所述的 20 倍]。我敢肯定,对功能齐全的对象进行真实世界的测试会是一个更好的比较。我运行的代码是这样的(我分别运行了几次测试):

var X,Y, x,y, i, intNow;

X = function() {};
X.prototype.message = function(s) { var mymessage = s + "";}
X.prototype.addition = function(i,j) { return (i *2 + j * 2) / 2; }

Y = function() {
  this.message = function(s) { var mymessage = s + "";}
  this.addition = function(i,j) { return (i *2 + j * 2) / 2; }
};


intNow = (new Date()).getTime();
for (i = 0; i < 10000000; i++) {
  y = new Y();
  y.message('hi');
  y.addition(i,2)
}
console.log((new Date()).getTime() - intNow); //FF=5206ms; Safari=1554

intNow = (new Date()).getTime();
for (i = 0; i < 10000000; i++) {
  x = new X();
  x.message('hi');
  x.addition(i,2)
}
console.log((new Date()).getTime() - intNow);//FF=3894ms;Safari=606

真的很遗憾,因为我真的很讨厌使用prototype。我喜欢我的目标代码是自我封装的,并且不允许漂移。不过,我想当速度很重要时,我别无选择。该死。

[编辑] 非常感谢@Kevin 指出我之前的代码是错误的,极大地提高了prototype 方法的报告速度。修复后,原型仍然明显更快,但差异不是那么大。

【讨论】:

  • 我还可以验证这个基准看起来是正确的……虽然我对 Safari 的低数字感到好奇。你用的是什么版本?在我的机器上,我看到:FireFox 3.6.8:5030/377,Safari 5.0:3037/264。
  • 查看时间分解也会很有趣——即实例化XY 需要多少时间,查找属性需要多少时间(例如, var tmp = x.message;) 以及调用属性需要多少时间(例如,x.message('hi'))。
  • @David Wolever - 我的 Safari 是 5.0.6553.16,最近才推出。虽然我在 Mac 上。我不知道为什么我不更多地使用 Safari。它的速度快得离谱,而且调试器比 Firebug 优越得多,但愚蠢的是我从不使用它,除非我必须这样做。我尝试了你的建议。单个属性查找比仅实例化增加了大约 10%。两种方法都显示出大致相同的增长。因此,使用这两种方法似乎都没有任何额外的成本或节省。那种感觉让我很惊讶。同样,最好用一个真实的例子来试试这个。
  • 刚刚在 Node.js v0.4.7 上运行了这个。结果是原型(与构造函数相比)快了大约 6 倍
  • 基准测试有点虚伪。您主要对“x = new X()”和“y = new Y()”进行基准测试,而不是函数调用。如果将 new 移到循环之外,那么两种方法的性能几乎相等。以下是结果:在 FF 上,新 => 13390 vs 9888,新外部 => 6153 vs 6066。在 Chrome 上(以及 10 倍以上的迭代),新内部 => 3253 vs 1247,新外部 => 311 vs 339 .
【解决方案3】:

直观地说,在原型上创建函数似乎更节省内存和更快:函数只创建一次,而不是每次创建新实例。

但是,当需要访问该功能时,性能会略有不同。当引用c.showMsg 时,JavaScript 运行时首先检查c 上的属性。如果没有找到,则检查c 的原型。

因此,在实例上创建属性会导致访问时间稍快一些 - 但这可能只是对于非常深的原型层次结构的问题。

【讨论】:

    【解决方案4】:

    我猜这取决于您要创建的对象的类型。我与 Andrew 进行了类似的测试,但使用的是静态对象,并且静态对象胜出。这是测试:

    var X, Y, Z, x, y, z;
    
    X = function() {};
    X.prototype.message = function(s) {
      var mymessage = s + "";
    }
    X.prototype.addition = function(i, j) {
      return (i * 2 + j * 2) / 2;
    }
    
    Y = function() {
      this.message = function(s) {
        var mymessage = s + "";
      }
      this.addition = function(i, j) {
        return (i * 2 + j * 2) / 2;
      }
    };
    
    Z = {
      message: function(s) {
        var mymessage = s + "";
      },
      addition: function(i, j) {
        return (i * 2 + j * 2) / 2;
      }
    }
    
    function TestPerformance() {
      var closureStartDateTime = new Date();
      for (var i = 0; i < 100000; i++) {
        y = new Y();
        y.message('hi');
        y.addition(i, 2);
      }
      var closureEndDateTime = new Date();
    
      var prototypeStartDateTime = new Date();
      for (var i = 0; i < 100000; i++) {
        x = new X();
        x.message('hi');
        x.addition(i, 2);
      }
      var prototypeEndDateTime = new Date();
    
      var staticObjectStartDateTime = new Date();
      for (var i = 0; i < 100000; i++) {
        z = Z; // obviously you don't really need this
        z.message('hi');
        z.addition(i, 2);
      }
      var staticObjectEndDateTime = new Date();
      var closureTime = closureEndDateTime.getTime() - closureStartDateTime.getTime();
      var prototypeTime = prototypeEndDateTime.getTime() - prototypeStartDateTime.getTime();
      var staticTime = staticObjectEndDateTime.getTime() - staticObjectStartDateTime.getTime();
      console.log("Closure time: " + closureTime + ", prototype time: " + prototypeTime + ", static object time: " + staticTime);
    }
    
    TestPerformance();

    此测试是我在以下位置找到的代码的修改:

    Link

    结果:

    IE6:关闭时间:1062,原型时间:766,静态对象时间:406

    IE8:关闭时间:781,原型时间:406,静态对象时间:188

    FF:关闭时间:233,原型时间:141,静态对象时间:94

    Safari:关闭时间:152,原型时间:12,静态对象时间:6

    Chrome:关闭时间:13,原型时间:8,静态对象时间:3

    吸取的教训是,如果您需要从同一个类中实例化许多不同的对象,那么将其创建为静态对象会胜出。因此,请仔细考虑您真正需要什么样的课程。

    【讨论】:

    • 好吧,这里至少应该有一个 +1 !感谢您分享您的想法和测试!!!当我不需要实例化多个对象的实例时,我通常在 JS 中使用静态对象(通常也使用其他语言,而不是使用单例)。我预计静态对象会更快,但我很高兴您在这里通过测试清楚地说明了这一点。再次感谢!
    • 很好的测试,这回答了我的 Javascript 设计问题!
    • 如果有人感兴趣,请向 jsperf.com 添加测试:jsperf.com/closure-prototype-static-performance
    • 这个测试只是一遍又一遍地重复使用 Z,这不是一个公平的测试,因为其他测试在 for 循环中有新的 X() 和新的 Y()。更公平的是创建一次 new X() 并在 for 循环中执行相同的操作。测试有点瑕疵。
    • @momomo 的评论非常相关。想知道为什么它没有得到更多的支持。对于单实例,闭包/原型比 Chrome 49.x 上的静态对象快约 2 倍
    【解决方案5】:

    因此,在实例上创建属性会导致访问时间稍快一些 - 但这可能只是对于非常深的原型层次结构的问题。

    实际上结果与我们预期的不同 - 访问原型方法的时间比访问完全附加到对象的方法更快(FF 测试)。

    【讨论】:

      【解决方案6】:

      所以我决定也测试一下。我测试了创建时间、执行时间和内存使用。我使用了 Nodejs v0.8.12 和运行在 Mac Book Pro 上的 mocha 测试框架,启动到 Windows 7。“快速”结果使用原型,“慢”结果使用模块模式。我为每种类型的对象创建了 100 万个,然后访问了每个对象中的 4 个方法。结果如下:

      c:\ABoxAbove>mocha test/test_andrew.js
      
      Fast Allocation took:170 msec
      ·Fast Access took:826 msec
      state[0] = First0
      Free Memory:5006495744
      
      ·Slow Allocation took:999 msec
      ·Slow Access took:599 msec
      state[0] = First0
      Free Memory:4639649792
      
      Mem diff:358248k
      Mem overhead per obj:366.845952bytes
      
      ? 4 tests complete (2.6 seconds)
      

      代码如下:

      var assert = require("assert"), os = require('os');
      
      function Fast (){}
      Fast.prototype = {
          state:"",
          getState:function (){return this.state;},
          setState:function (_state){this.state = _state;},
          name:"",
          getName:function (){return this.name;},
          setName:function (_name){this.name = _name;}
      };
      
      function Slow (){
          var state, name;
          return{
              getState:function (){return this.state;},
              setState:function (_state){this.state = _state;},
              getName:function (){return this.name;},
              setName:function (_name){this.name = _name;}
          };
      }
      describe('test supposed fast prototype', function(){
          var count = 1000000, i, objs = [count], state = "First", name="Test";
          var ts, diff, mem;
          it ('should allocate a bunch of objects quickly', function (done){
              ts = Date.now ();
              for (i = 0; i < count; ++i){objs[i] = new Fast ();}
              diff = Date.now () - ts;
              console.log ("Fast Allocation took:%d msec", diff);
              done ();
          });
          it ('should access a bunch of objects quickly', function (done){
              ts = Date.now ();
              for (i = 0; i < count; ++i){
                  objs[i].setState (state + i);
                  assert (objs[i].getState () === state + i, "States should be equal");
                  objs[i].setName (name + i);
                  assert (objs[i].getName () === name + i, "Names should be equal");
              }
              diff = Date.now() - ts;
              console.log ("Fast Access took:%d msec", diff);
              console.log ("state[0] = " + objs[0].getState ());
              mem = os.freemem();
              console.log ("Free Memory:" + mem + "\n");
              done ();
          });
          it ('should allocate a bunch of objects slowly', function (done){
              ts = Date.now ();
              for (i = 0; i < count; ++i){objs[i] = Slow ();}
              diff = Date.now() - ts;
              console.log ("Slow Allocation took:%d msec", diff);
              done ();
          });
          it ('should access a bunch of objects slowly', function (done){
              ts = Date.now ();
              for (i = 0; i < count; ++i){
                  objs[i].setState (state + i);
                  assert (objs[i].getState () === state + i, "States should be equal");
                  objs[i].setName (name + i);
                  assert (objs[i].getName () === name + i, "Names should be equal");
              }
              diff = Date.now() - ts;
              console.log ("Slow Access took:%d msec", diff);
              console.log ("state[0] = " + objs[0].getState ());
              var mem2 = os.freemem();
              console.log ("Free Memory:" + mem2 + "\n");
              console.log ("Mem diff:" + (mem - mem2) / 1024 + "k");
              console.log ("Mem overhead per obj:" + (mem - mem2) / count + 'bytes');
              done ();
          });
      });
      

      结论:这支持了这篇文章中其他人的发现。如果您不断创建对象,那么原型机制显然更快。如果您的代码大部分时间都在访问对象,那么模块模式会更快。如果您对内存使用敏感,那么原型机制每个对象使用的字节数减少了约 360 字节。

      【讨论】:

      • 我不是 JavaScript 老师,但我创建了这个测试来测试访问时的性能,这里是:jsperf.com/accessing-prototyped-and-static-objects
      • 360 bytes 不是固定的——它取决于您设置的属性数量及其值,以及引擎可能运行的任何优化。
      【解决方案7】:

      I ran my own tests.

      第一个结论是,静态访问实际上比真正的原型设计要慢。有趣的是,the Version 23 of this test 有一个有缺陷的原型(变量 X),它只是一遍又一遍地返回完全覆盖的原型对象,当我创建我的测试时,这个原型仍然比我的“真正的原型”测试慢。

      无论如何,回答:除非我的测试有缺陷,否则它表明真正的原型设计是最快的。忽略实例化时,它优于或至少等于静态对象。实例化和私有变量的 this 赋值都慢得多。我没想到私有变量会这么慢。

      我可能会感兴趣的是,我在其间使用 jQuery.extend 扩展了原型 Object,它的速度与直接分配的速度大致相同。当然,扩展超出了测试本身。至少这是一种避免编写烦人的“.prototype”的方法。-一直都是零件。

      【讨论】:

        【解决方案8】:

        高分辨率浏览器性能 API 测试

        这里的测试都没有利用performance API 进行高分辨率测试,所以我写了一个可以显示许多不同场景的当前最快结果,其中 2 个在大多数运行中比任何其他答案都快。

        每个类别都禁食(10,000 次迭代)

        • 仅限属性访问(~0.5ms){ __proto__: Type }
        • 使用属性访问创建循环对象(:Object.create(Type)

        代码使用 ES6 没有 babel 转译,以确保准确性。它适用于当前的 chrome。运行下面的测试以查看故障。

        function profile () {
          function test ( name
                        , define
                        , construct
                        , { index = 0
                          , count = 10000
                          , ordinals = [ 0, 1 ]
                          , constructPrior = false
                          } = {}
                        ) {
            performance.clearMarks()
            performance.clearMeasures()
            const symbols = { type: Symbol('type') }
            const marks = (
              { __proto__: null
              , start: `${name}_start`
              , define: `${name}_define`
              , construct: `${name}_construct`
              , end: `${name}_end`
              }
            )
        
            performance.mark(marks.start)
            let Type = define()
            performance.mark(marks.define)
        
            let obj = constructPrior ? construct(Type) : null
            do {
              if(!constructPrior)
                obj = construct(Type)
              if(index === 0)
                performance.mark(marks.construct)
        
              const measureOrdinal = ordinals.includes(index)
              if(measureOrdinal)
                  performance.mark(`${name}_ordinal_${index}_pre`)
        
              obj.message('hi')
              obj.addition(index, 2)
        
              if(measureOrdinal)
                performance.mark(`${name}_ordinal_${index}_post`)
            } while (++index < count)
            performance.mark(marks.end)
        
            const measureMarks = Object.assign (
              { [`${name}_define`]: [ marks.start, marks.define ]
              , [`${name}_construct`]: [ marks.define, marks.construct ]
              , [`${name}_loop`]: [ marks.construct, marks.end ]
              , [`${name}_total`]: [ marks.start, marks.end ]
              }
            , ordinals.reduce((reduction, i) => Object.assign(reduction, { [`${name}_ordinal_${i}`]: [ `${name}_ordinal_${i}_pre`, `${name}_ordinal_${i}_post` ] }), {})
            )
        
            Object.keys(measureMarks).forEach((key) => performance.measure(key, ...measureMarks[key]))
        
            const measures = performance.getEntriesByType('measure').map(x => Object.assign(x, { endTime: x.startTime + x.duration }))
            measures.sort((a, b) => a.endTime - b.endTime)
            const durations = measures.reduce((reduction, measure) => Object.assign(reduction, { [measure.name]: measure.duration }), {})
        
            return (
              { [symbols.type]: 'profile'
              , profile: name
              , duration: durations[`${name}_total`]
              , durations
              , measures
              }
            )
          }
        
          const refs = (
            { __proto__: null
            , message: function(s) { var mymessage = s + '' }
            , addition: function(i, j) { return (i *2 + j * 2) / 2 }
            }
          )
        
          const testArgs = [
            [ 'constructor'
            , function define() {
                return function Type () {
                  this.message = refs.message
                  this.addition = refs.addition
                }
              }
            , function construct(Type) {
                return new Type()
              }
            ]
          , [ 'prototype'
            , function define() {
                function Type () {
                }
                Type.prototype.message = refs.message
                Type.prototype.addition = refs.addition
                return Type
              }
            , function construct(Type) {
                return new Type()
              }
            ]
          , [ 'Object.create'
            , function define() {
                return (
                  { __proto__: null
                  , message: refs.message
                  , addition: refs.addition
                  }
                )
              }
            , function construct(Type) {
                return Object.create(Type)
              }
            ]
          , [ 'proto'
            , function define() {
                return (
                  { __proto__: null
                  , message: refs.message
                  , addition: refs.addition
                  }
                )
              }
            , function construct(Type) {
                return { __proto__: Type }
              }
            ]
          ]
        
          return testArgs.reduce(
            (reduction, [ name, ...args ]) => (
              Object.assign( reduction
              , { [name]: (
                    { normal: test(name, ...args, { constructPrior: true })
                    , reconstruct: test(`${name}_reconstruct`, ...args, { constructPrior: false })
                    }
                  )
                }
              )
            )
          , {})
        }
        
        let profiled = profile()
        const breakdown = Object.keys(profiled).reduce((reduction, name) => [ ...reduction, ...Object.keys(profiled[name]).reduce((r, type) => [ ...r, { profile: `${name}_${type}`, duration: profiled[name][type].duration } ], []) ], [])
        breakdown.sort((a, b) => a.duration - b.duration)
        try {
          const Pre = props => React.createElement('pre', { children: JSON.stringify(props.children, null, 2) })
          
          ReactDOM.render(React.createElement(Pre, { children: { breakdown, profiled } }), document.getElementById('profile'))
        } catch(err) {
            console.error(err)
        }
        <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
        
        <div id="profile"></div>

        【讨论】:

          【解决方案9】:

          我们需要将对象的构造和使用分开。

          在原型上声明函数时,它在所有实例之间共享。在构造函数中声明函数时,每次创建新实例时都会重新创建 this。鉴于此,我们需要分别对构建和使用进行基准测试以获得更好的结果。这就是我所做的,并想与您分享结果。此基准不测试施工速度。

          function ThisFunc() {
              this.value = 0;
              this.increment = function(){
                  this.value++;
              }
          }
          
          function ProtFunc() {
              this.value = 0;
          }
          
          ProtFunc.prototype.increment = function (){
              this.value++;
          }
          
          function ClosFunc() {
              var value = 0;
          
              return {
                  increment:function(){
                      value++;
                  }
              };
          }
          
          var thisInstance = new ThisFunc;
          
          var iterations = 1000000;
          var intNow = (new Date()).getTime();
          for (i = 0; i < iterations; i++) {
              thisInstance.increment();
          }
          console.log(`ThisFunc: ${(new Date()).getTime() - intNow}`); // 27ms node v4.6.0
          
          var protInstance = new ProtFunc;
          intNow = (new Date()).getTime();
          for (i = 0; i < iterations; i++) {
              protInstance.increment();
          }
          console.log(`ProtFunc: ${(new Date()).getTime() - intNow}`); // 4ms node v4.6.0
          
          var closInstance = ClosFunc();
          intNow = (new Date()).getTime();
          for (i = 0; i < iterations; i++) {
              closInstance.increment();
          }
          console.log(`ClosFunc: ${(new Date()).getTime() - intNow}`); // 7ms node v4.6.0
          

          从这些结果我们可以看出原型版本最快(4ms),但闭包版本非常接近(7ms)。您可能仍需要针对您的特定情况进行基准测试。

          所以:

          • 当我们需要拥有所有性能或在实例之间共享功能时,我们可以使用原型版本。
          • 如果我们想要的是它们提供的功能,我们可以使用其他版本。 (私有状态封装、可读性等)

          PS:我以安德鲁的回答作为参考。使用相同的循环和符号。

          【讨论】:

            【解决方案10】:

            虽然很有趣。这并不取决于您创建哪种类型的对象,而重要的是您如何编写示例。同样,我运行了与 shmuel613 类似的测试,后者以 Andrew 的身份编写了类似的测试。第一个测试是创建一个构造函数、一个类和一个对象字面量的单个实例,然后测量构造函数的实例函数、类的原型方法和对象字面量的静态函数的执行速度:

            var Y, Z, x, y, z;
            
            class X {
                message(s) {
                    var mymessage = s + "";
                };
                addition(i, j) {
                    return (i * 2 + j * 2) / 2;
                };
            };
            
            Y = function () {
                this.message = function (s) {
                    var mymessage = s + "";
                };
                this.addition = function (i, j) {
                    return (i * 2 + j * 2) / 2;
                };
            };
            
            Z = {
                message(s) {
                    var mymessage = s + "";
                },
                addition(i, j) {
                    return (i * 2 + j * 2) / 2;
                }
            }
            
            function TestPerformance() {
                console.time("Closure time:");
                y = new Y(); // create a single instance
                for (var i = 0; i < 100000; i++) {
                    // I am comparing a single instance with the other single instances
                    y.message('hi');
                    y.addition(i, 2);
                }
                console.timeEnd("Closure time:");
            
                console.time("Prototype time:");
                x = new X(); // create a single instance
                for (var i = 0; i < 100000; i++) {
                    // I am comparing a single instance with the other single instances
                    x.message('hi');
                    x.addition(i, 2);
                }
                console.timeEnd("Prototype time:");
            
                console.time("Static object time:");
                for (var i = 0; i < 100000; i++) {
                    z = Z; // obviously you don't really need this
                    z.message('hi');
                    z.addition(i, 2);
                }
                console.timeEnd("Static object time:");
            }
            
            TestPerformance();
            

            第二个测试测量创建许多构造函数实例、类和对象字面量的执行速度,然后执行实例函数、原型方法和静态方法:

            var Y, x, y, z;
            
            class X {
                message(s) {
                    var mymessage = s + "";
                };
                addition(i, j) {
                    return (i * 2 + j * 2) / 2;
                };
            };
            
            Y = function () {
                this.message = function (s) {
                    var mymessage = s + "";
                };
                this.addition = function (i, j) {
                    return (i * 2 + j * 2) / 2;
                };
            };
            
            function TestPerformance() {
                console.time("Closure time:");
                //y = new Y()
                for (var i = 0; i < 100000; i++) {
                    y = new Y(); // creating an instance
                    y.message('hi');
                    y.addition(i, 2);
                }
                console.timeEnd("Closure time:");
            
                console.time("Prototype time:");
                //x = new X();
                for (var i = 0; i < 100000; i++) {
                    x = new X(); // creating an instance
                    x.message('hi');
                    x.addition(i, 2);
                }
                console.timeEnd("Prototype time:");
            
                console.time("Static object time:");
                for (var i = 0; i < 100000; i++) {
                    z = { 
                        message(s) {
                            var mymessage = s + "";
                        },
                        addition(i, j) {
                            return (i * 2 + j * 2) / 2;
                        }
                    }; // creating an instance such as from factory functions
                    z.message('hi');
                    z.addition(i, 2);
                }
                console.timeEnd("Static object time:");
            }
            
            TestPerformance();
            

            吸取的教训是,不要盲目地发展对某事的偏见而不彻底。构造函数的实例函数(ES2016 之前的类)的执行速度和类的原型方法的执行速度实际上与对象的静态函数的执行速度一样快。然而,具有实例函数的构造函数实例的创建速度与执行速度与具有原型方法的类实例的创建速度与具有静态方法的对象字面量的创建速度表明,具有原型方法的类在 Chrome 上创建和执行速度更快、Microsoft edge 和 Opera。使用静态方法创建对象字面量的速度仅在 Mozilla firefox 中更快

            【讨论】:

              猜你喜欢
              • 2017-12-13
              • 1970-01-01
              • 2019-05-12
              • 2019-03-03
              • 1970-01-01
              • 1970-01-01
              • 2017-11-20
              • 1970-01-01
              • 2021-12-16
              相关资源
              最近更新 更多