Javascript原型操作员性能:节省内存,但速度更快吗?
我读过使用prototype操作符向Javascript类添加方法的文章还节省了内存 然后我读到了“用一堆原型属性实例化一个函数是非常、非常、快速的”,但他是在谈论以标准方式使用原型,还是在他的文章中谈论他的具体例子 例如,正在创建此对象:Javascript原型操作员性能:节省内存,但速度更快吗?,javascript,performance,function-prototypes,Javascript,Performance,Function Prototypes,我读过使用prototype操作符向Javascript类添加方法的文章还节省了内存 然后我读到了“用一堆原型属性实例化一个函数是非常、非常、快速的”,但他是在谈论以标准方式使用原型,还是在他的文章中谈论他的具体例子 例如,正在创建此对象: function Class1() { this.showMsg = function(string) { alert(string); } } var c = new Class1(); c.showMsg(); 比创建此对象慢,那么 functi
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静态对象之间的性能比较感兴趣的人可以阅读静态对象肯定更快,显然,只有当您不需要对象的多个实例时,才可以使用它们。我确信,就实例化对象而言,它的速度更快,而且占用的内存更少,这一点毫无疑问,但我认为javascript引擎需要遍历对象的所有属性,以确定调用的属性/方法是否是该对象的一部分,如果不是,则检查原型。我不是100%确定这一点,但我假设这就是它的工作原理,如果是这样,那么在某些情况下,如果您的对象添加了很多方法,只实例化了一次,并且大量使用,那么它可能会稍微慢一点,但这只是一个假设,我没有测试任何东西
但最后,我还是同意,作为一般规则,使用原型会更快。这是一个有趣的问题,所以我运行了一些非常简单的测试(我应该重新启动浏览器以清除内存,但我没有;这是值得的)。至少在Safari和Firefox上,
prototype
运行速度明显加快[编辑:不是前面提到的20倍]。我相信使用功能齐全的对象进行真实世界的测试会是一个更好的比较。我运行的代码如下(我分别运行了几次测试):
var X,Y,X,Y,i,intNow;
X=函数(){};
X.prototype.message=函数{var mymessage=s+“”;}
X.prototype.addition=函数(i,j){返回(i*2+j*2)/2;}
Y=函数(){
this.message=函数{var mymessage=s+“”;}
this.addition=函数(i,j){返回(i*2+j*2)/2;}
};
intNow=(新日期()).getTime();
对于(i=0;i<10000000;i++){
y=新的y();
y、 信息(“嗨”);
y、 增补(一、二)
}
log((new Date()).getTime()-intNow)//FF=5206ms;Safari=1554
intNow=(新日期()).getTime();
对于(i=0;i<10000000;i++){
x=新的x();
x、 信息(“嗨”);
x、 增补(一、二)
}
log((new Date()).getTime()-intNow)//FF=3894ms;Safari=606
直观地说,在原型上创建函数似乎更高效、更快:函数只创建一次,而不是每次创建一个新实例
但是,在访问该函数时,性能会略有不同。当引用c.showMsg
时,JavaScript运行时首先检查c
上的属性。如果未找到,则检查c
的原型
因此,在实例上创建属性将导致访问时间稍微加快—但这可能只是非常深层的原型层次结构的问题。我想这取决于您要创建的对象类型。我运行了一个与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();
var X,Y,Z,X,Y,Z;
X=函数(){};
X.prototype.message=函数{var mymessage=s+“”;}
X.prototype.addition=函数(i,j){返回(i*2+j*2)/2;}
Y=函数(){
this.message=函数{var mymessage=s+“”;}
this.addition=函数(i,j){返回(i*2+j*2)/2;}
};
Z={
消息:函数{var mymessage=s+“”;}
,加法:函数(i,j){返回(i*2+j*2)/2;}
}
函数TestPerformance()
{
var closureStartDateTime=新日期();
对于(变量i=0;i<100000;i++)
{
y=新的y();
y、 信息(“嗨”);
y、 添加(i,2);
}
var closureEndDateTime=新日期();
var prototypeStartDateTime=新日期();
对于(变量i=0;i<100000;i++)
{
x=新的x();
x、 信息(“嗨”);
x、 添加(i,2);
}
var prototypeEndDateTime=新日期();
var staticObjectStartDateTime=新日期();
对于(变量i=0;i<100000;i++)
{
z=z;//显然你并不真的需要这个
z、 信息(“嗨”);
z、 添加(i,2);
}
var staticObjectEndDateTime=新日期();
var closureTime=closureEndDateTime.getTime()-closureStartDateTime.getTime();
var prototypeTime=prototypeEndDateTime.getTime()-prototypeStartDateTime.getTime();
var staticTime=staticObjectEndDateTime.getTime()-staticObjectStartDateTime.getTime();
log(“关闭时间:“+closureTime+”,原型时间:“+prototypeTime+”,静态对象时间:“+staticTime”);
}
TestPerformance();
此测试是对我在以下位置找到的代码的修改:
结果:
IE6:关闭时间:1062,原型时间:766,静态对象时间:406
IE8:关闭时间:781,原型时间:406,静态对象时间:188
FF:关闭时间:233,原型时间:141,静态对象时间:94
Safari:关闭时间:152,原型时间:12,静态对象时间:6
Chrome:关闭时间:13,原型时间:8,静态对象时间:3
吸取的教训是,如果您不需要实例化同一类中的许多不同对象,那么将其创建为静态对象将轻而易举地获胜。所以仔细想想你真正需要什么样的课程
因此,在实例上创建属性将导致
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 ();
});
});
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