我有以下3种不同的方式来创建对象实例。
我想知道其中一个更快,占用更少的内存,为什么?
//Option 1
export interface Animal1 {
name: string;
color: string;
isHungry: boolean;
}
let animal: Animal1 = {
name: 'cat',
color: 'Brown',
isHungry: true
};
animal1.name = 'cat';
animal1.color = 'brown';
animal1.isHungry = true;
//Option 2
export class Animal2 {
name: string;
color: string;
isHungry: boolean;
}
let animal2: Animal2 = new Animal2();
animal2.name = 'cat';
animal2.color = 'brown';
animal2.isHungry = true;
//Option 3
export class Animal3 {
constructor(public name:string, public color:string, public isHungry:boolean) {}
}
let animal3 = new Animal3('cat', 'brown', true);
在编码风格和维护方面,我更喜欢在单元测试中使用带有构建器类的选项1。选项3最受欢迎,因为它是:
这三个之间在性能/内存上有什么区别吗?
答案 0 :(得分:3)
在JavaScript引擎中高度优化了对象实例的创建。速度将受周围代码,运行频率,运行时版本和许多其他因素的影响。
很抱歉,这不是您想要的答案。
就内存而言,您可以简单地数出每种方法创建的对象-但是除非您编写了高度优化的JavaScript(不太可能),否则这将毫无意义。
通常,您对对象创建模式的选择不应取决于性能,而应取决于非功能性要求,例如团队同意的代码样式,可维护性和API形状。
当然,仍可以使用通常的方法来分析用TS或JS 编写的算法的时间和空间复杂性。
答案 1 :(得分:3)
与JavaScript中的相同。对象创建时间可能没有什么区别,但是对使用这些类型的代码的整体性能有明显的影响。这些选项不相等。
原因是“隐藏类” JIT优化以及JIT可以用单态代码完成的事情。如果对象成员总是以相同的顺序初始化,则JIT可以为所有类型实例分配相同的“隐藏类”,然后使用此信息通过内存偏移量(而不是昂贵的哈希表查找)访问类成员。当您遍历具有相同隐藏类的对象的集合(或使用具有相同隐藏类的参数重复调用该函数)时,JIT可以识别单态代码并使用省略的过多类型检查编译该函数的专用版本,这是动态内联方法调用,并执行其他一些使现代JS VM如此快速的魔术。
因此,通常,单态代码比多态代码快,并且JIT使用属性初始化的顺序来确定“内部对象类型”。
https://draft.li/blog/2016/12/22/javascript-engines-hidden-classes/
https://richardartoul.github.io/jekyll/update/2015/04/26/hidden-classes.html
启用这些优化的最简单,最安全的方法是使用类,并确保所有类成员始终在其构造函数中以相同顺序初始化,这是示例中的选项3。选项2最糟糕,因为不能保证不同类实例的“隐藏类”是相同的,并且JIT不会认为它们具有相同的类型。
最后但并非最不重要的。 JS JIT性能没有明显的表现。 JIT引擎不仅使用略有不同(但非常复杂)的优化策略,而且每次都在发展,这使得有关JIT内部的大多数文章在相当短的时间内就被淘汰了。但是,允许JIT利用单态代码的“隐藏类”或类似的优化是JS JIT性能的基础。
无论如何,不要猜测性能,也不相信别人说的看似明显的话。测量它。