在JavaScript中,我们有两种方法可以创建“类”并赋予它公共功能。
方法1:
function MyClass() {
var privateInstanceVariable = 'foo';
this.myFunc = function() { alert(privateInstanceVariable ); }
}
方法2:
function MyClass() { }
MyClass.prototype.myFunc = function() {
alert("I can't use private instance variables. :(");
}
我已经多次读过使用方法2的人saying,因为所有实例共享相同的函数副本而不是每个实例都拥有自己的副本。通过原型定义函数有一个巨大的缺点 - 它使得无法拥有私有实例变量。
尽管从理论上讲,使用方法1给对象的每个实例赋予了它自己的函数副本(因此使用了更多的内存,更不用说分配所需的时间) - 这是实际发生的事情吗?似乎优化Web浏览器可以很容易地识别这种非常常见的模式,并且实际上让对象的所有实例引用通过这些“构造函数”定义的函数的相同副本。然后,如果稍后明确更改它,它只能为实例提供自己的函数副本。
任何洞察力 - 或者更好的现实世界体验 - 关于两者之间的性能差异,都会非常有帮助。
答案 0 :(得分:61)
请参阅http://jsperf.com/prototype-vs-this
通过原型声明你的方法更快,但这是否相关是值得商榷的。
如果您的应用程序中存在性能瓶颈,则不太可能出现这种情况,例如,除非您碰巧在某些任意动画的每一步中实例化10000多个对象。
如果性能是一个严重的问题,并且你想进行微优化,那么我建议通过原型声明。否则,只需使用对您最有意义的模式。
我要补充一点,在JavaScript中,有一种前缀属性的约定,这些属性旨在被视为私有的下划线(例如_process()
)。大多数开发人员会理解并避免这些属性,除非他们愿意放弃社会契约,但在这种情况下,你可能也不会满足于他们。我的意思是:你可能不需要 true 私有变量......
答案 1 :(得分:2)
在Chrome的新版本中,this.method比prototype.method快约20%,但创建新对象的速度仍然较慢。
如果您可以重复使用该对象而不是始终创建一个新对象,则可以比创建新对象快50%-90%。加上没有垃圾收集的好处,这是巨大的:
答案 2 :(得分:1)
只有在创建大量实例时才会有所作为。否则,在两种情况下调用成员函数的性能都完全相同。
我在jsperf上创建了一个测试用例来证明这一点:
答案 3 :(得分:1)
您可能没有考虑过这一点,但直接将方法放在对象上实际上更好:
然而,速度差异几乎可以忽略不计。最重要的是,将方法放在原型上会有两种更有效的方法:
正如詹姆斯所说,如果要实例化数千个类的实例,这种差异可能很重要。
也就是说,我当然可以想象一个JavaScript引擎,它识别出你附加到每个对象的函数不会在实例之间发生变化,因此只保留函数的一个副本在内存中,所有实例方法都指向共享函数。事实上,似乎Firefox正在做一些像这样的特殊优化,但Chrome不是。
<强> ASIDE:强>
你是对的,无法从原型的内部方法访问私有实例变量。所以我想你必须问自己的问题是,你是否重视能否使实例变量真正私有而不是利用继承和原型设计?我个人认为将变量设为真正的私有并不重要,只会使用下划线前缀(例如“this._myVar”)来表示尽管变量是公共的,但应该认为它是私有的。也就是说,在ES6中,显然有一种方法可以同时拥有这两个世界!
答案 4 :(得分:0)
简而言之,使用方法2来创建所有实例将共享的属性/方法。这些将是“全球性的”,对它的任何改变都将反映在所有实例中。使用方法1创建特定于实例的属性/方法。
我希望我有更好的参考,但现在看看this。您可以看到我如何在同一个项目中使用这两种方法用于不同的目的。
希望这会有所帮助。 :)
答案 5 :(得分:0)
这个答案应该被视为填补缺失点的其余答案的扩展。个人经验和基准都包含在内。
就我的经验而言,我使用构造函数来虔诚地构建我的对象,无论方法是否是私有的。主要原因是,当我开始时,这对我来说是最简单的方法,所以它不是特别的偏好。它可能就像我喜欢可见的封装一样简单,原型有点无实体。我的私有方法也将被指定为范围中的变量。虽然这是我的习惯,并且保持良好的自我控制,但它并不总是最好的习惯,我有时会碰壁。除了根据配置对象和代码布局进行高度动态自组装的古怪场景之外,在我看来,它往往是较弱的方法,特别是如果性能是一个问题。知道内部是私有的是有用的,但你可以通过其他方式通过正确的规则来实现。除非性能是一个重要的考虑因素,否则请使用最适合手头任务的方法。
prototype.m = f
,this.m = f
和this.m = function...
之间,后者的表现明显优于前两个表现相同的表现。如果单独的原型查找是一个重要问题,那么最后两个函数将显着地执行第一个。相反,至少在金丝雀关注的地方还有其他奇怪的事情发生。它的可能功能根据它们的成员进行优化。许多性能考虑因素都在发挥作用。参数访问和变量访问也存在差异。免责声明:
答案 6 :(得分:-1)
您可以使用这种方法,它将允许您使用prototype
并访问实例变量。
var Person = (function () {
function Person(age, name) {
this.age = age;
this.name = name;
}
Person.prototype.showDetails = function () {
alert('Age: ' + this.age + ' Name: ' + this.name);
};
return Person; // This is not referencing `var Person` but the Person function
}()); // See Note1 below
注意1:
括号将调用该函数(自调用函数)并将结果分配给var Person
。
用法
var p1 = new Person(40, 'George');
var p2 = new Person(55, 'Jerry');
p1.showDetails();
p2.showDetails();