Javascript原型操作员性能:节省内存,但速度更快吗?

Mar*_*aio 48 javascript performance function-prototypes

在这里阅读(Douglas Crockford)使用原型运算符向Javascript类添加方法也保存了内存.

然后我读到了John Resig的文章 "用一堆原型属性实例化一个函数是非常非常快的 ",但他是在谈论以标准方式使用原型,还是他在他的文章中谈论他的具体例子?

例如,正在创建此对象:

function Class1()
{
   this.showMsg = function(string) { alert(string); }
}
var c = new Class1();
c.showMsg();
Run Code Online (Sandbox Code Playgroud)

创建这个对象吗?

function Class1() {}
Class1.prototype.showMsg = function(string) { alert(string); }
var c = new Class1();
c.showMsg();
Run Code Online (Sandbox Code Playgroud)

PS

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


编辑:对于JS对象和JS静态对象之间的性能比较它可能感兴趣的人可以阅读下面的答案.静态对象肯定更快,显然只有在不需要多个对象实例时才能使用它们.

And*_*rew 60

这是一个有趣的问题,所以我运行了一些非常简单的测试(我应该重新启动我的浏览器以清除内存,但我没有;为了它的价值而拿这个).它看起来至少在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 < 1000000; 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 < 1000000; i++) {
    x = new X();
    x.message('hi');
    x.addition(i,2)
}
console.log((new Date()).getTime() - intNow);//FF=3894ms;Safari=606
Run Code Online (Sandbox Code Playgroud)

这是一个真正的耻辱,因为我真的很讨厌使用prototype.我喜欢我的目标代码是自封装的,不允许漂移.我想当速度很重要时,我没有选择.该死.

[编辑]非常感谢@Kevin,他指出我以前的代码是错误的,大大提高了报告的prototype方法速度.固定后,原型仍然明显加快,但差异并不大.

  • 只需在Node.js v0.4.7上运行它.对于原型(与构造函数)相比,结果约为**6x**. (3认同)

shm*_*613 32

我猜这取决于你想要创建的对象的类型.我和安德鲁进行了类似的测试,但是使用静态对象,静态对象赢了.这是测试:

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();
Run Code Online (Sandbox Code Playgroud)

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

http://blogs.msdn.com/b/kristoffer/archive/2007/02/13/javascript-prototype-versus-closure-execution-speed.aspx

结果:

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

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

FF:关闭时间:233,原型时间:141,静态物体时间:94

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

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

吸取的教训是,如果你不要有一个需要从同一个类实例化许多不同的对象,然后创建它作为一个静态对象手中夺了下来.所以仔细想想你真正需要什么样的课程.

  • 这个测试只是一遍又一遍地重复使用Z,这不是一个公平的测试,因为其他人在for循环中有新的X()和新的Y().更公平的是创建新的X()一次并在for循环中执行相同的操作.测试有点缺陷. (11认同)
  • @ momomo的评论如此相关.不知道为什么它没有更多的投资.对于单个实例,闭包/原型比Chrome 49.x上的静态对象快约2倍 (2认同)

小智 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)
Run Code Online (Sandbox Code Playgroud)

代码如下:

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 ();
    });
});
Run Code Online (Sandbox Code Playgroud)

结论:这支持了本文中其他人发现的内容.如果您经常创建对象,那么原型机制显然更快.如果您的代码花费大部分时间访问对象,那么模块模式会更快.如果您对内存使用很敏感,那么原型机制每个对象使用约360个字节.