在JavaScript中,一个通常被吹捧的良好性能原则是避免改变对象的形状。
这让我想知道,这是
angular.module("myApp").service('instanceC', ClassC);
angular.module("myApp").controller('myController', function (instanceC) {
// Everything has been resolved
});
一种有价值的最佳做法,可以提供比此更好的性能
class factory {
constructor(ClassA, ClassB, ClassC) {
this.ClassA = ClassA;
this.ClassB = ClassB;
this.ClassC = ClassC;
}
createB(customParamForClassB) {
return new this.ClassB(customParamForClassB, this.ClassA)
}
}
angular.module("myApp").service('factory', factory);
angular.module("myApp").controller('myController', function (factory) {
let instanceB = factory.createB('myparams');
});
这是真是假?为什么?在一个JS引擎中,它是否或多或少与其他引擎相比真实存在?
答案 0 :(得分:11)
V8开发人员。
是的,第一个版本通常是值得的最佳实践。
原因是不对象创建本身会更快。相反,很明显,没有做任何工作的构造函数至少会比构建函数做得更快一些。
推荐使用第一个版本的原因是因为它确保应用程序中的所有Foo
对象具有相同的"形状",而对于第二个版本,可能会发生某些他们有.bar
财产,而其他人则没有。有时存在的属性有时不会强制JavaScript引擎远离它可以使用的最快的状态/代码路径;当有不止一个这样的财产时,效果会大得多。
举个例子:
class Foo() {
constructor() {}
addBar(x) { this.bar = x; }
addBaz(x) { this.baz = x; }
addQux(x) { this.qux = x; }
}
var foo1 = new Foo(); foo1.addBar(1);
var foo2 = new Foo(); foo2.addBaz(10); foo2.addBar(2);
var foo3 = new Foo(); foo3.addQux(100); foo3.addBaz(20); foo3.addBar(3);
function hot_function(foo) {
return foo.bar; // [1]
}
hot_function(foo1);
hot_function(foo2);
hot_function(foo3);
在标有[1]
的行上,使用此版本的构造函数,可以看到至少三种不同形状的对象。因此,JavaScript引擎将在对象中的至少三个不同位置找到属性bar
。根据其内部实现细节,它可能每次都必须搜索所有对象的属性,或者它可以缓存之前看到的对象形状,但缓存几个比缓存一个更昂贵,并且会有限制到缓存尝试。
但是,如果构造函数已将所有属性初始化为undefined
,则此处的所有传入foo
对象将具有相同的形状,bar
属性将始终是它们的第一个属性,并且引擎可以使用非常快的代码来处理这个非常简单的案例。
它不仅仅是这样的负载:而且addBar()
根据它是否可以简单地覆盖现有属性(非常快)而不同的内容会有所不同,必须添加一个新属性(可能更慢,可能需要分配和复制对象),或者必须在两种情况之间动态决定(当然最慢)。
另一个影响是每个唯一的对象形状将需要一些内部元数据。因此,避免不必要的不同对象形状将节省一些内存。
当然,对于这么小的例子,任何影响都会很小。但是,一旦你有一个拥有数千个对象的大型应用程序,每个对象都有几十个属性,它可以产生很大的不同。注意误导性微基准测试!