Javascript 对象大 O
Javascript Object Big-O
来自Java,Javascript对象让我想起了Java中的HashMap。
Java脚本:
var myObject = {
firstName: "Foo",
lastName: "Bar",
email: "foo@bar.com"
};
Java:
HashMap<String, String> myHashMap = new HashMap<String, String>();
myHashMap.put("firstName", "Foo");
myHashMap.put("lastName", "Bar");
myHashMap.put("email", "foo@bar.com");
在JavaHashMap中,它使用键的hashcode()函数来确定用于存储和检索的桶位置(条目)。大多数时候,对于 put() 和 get() 等基本操作,性能是常数时间,直到发生哈希冲突,对于这些基本操作变为 O(n),因为它形成一个链表以存储条目冲突。
我的问题是:
- Java脚本如何存储对象?
- 操作的性能如何?
- 是否会像 Java
那样发生任何碰撞或其他会降低性能的情况
谢谢!
Javascript 看起来像是将内容存储在地图中,但通常情况并非如此。您可以访问对象的大多数属性,就好像它们是映射中的索引一样,并在运行时分配新属性,但支持代码比仅使用映射更快、更复杂。
没有什么要求 VM 不使用映射,但大多数尝试检测对象的结构并为该结构创建有效的内存表示。当程序 运行 时,这会导致大量优化(和取消优化),这是一个非常复杂的情况。
This blog post,在@Zirak 的问题评论中链接,对常见结构以及 VM 何时可以从结构切换到映射进行了很好的讨论。它通常看起来不可预测,但主要基于 VM 中的一组启发式方法以及它认为它已经看到了多少不同的对象。这在很大程度上与 return 值的属性(及其类型)有关,并且往往以每个函数(尤其是构造函数)为中心。
有一些问题和文章深入细节(但希望在没有大量背景的情况下仍然可以理解):
- Why is getting a member faster than calling hasOwnProperty?
- http://mrale.ph/blog/2013/08/14/hidden-classes-vs-jsperf.html(以及本博客的其余部分)
根据以上情况,性能差异很大。最坏的情况应该是映射访问,最好的情况是直接内存访问(甚至可能是 deref)。
有很多场景可能会影响性能,特别是考虑到 JITter 和 VM 如何在运行时创建和销毁隐藏的 类,因为它们会看到对象的新变体。突然遇到一个之前被认为是单态的对象的新变体会导致 VM 切换回不太理想的表示并停止将该对象视为内存中的结构,但围绕它的逻辑非常复杂而且很好-涵盖在 this blog post.
您可以通过确保从同一构造函数创建的对象往往具有非常相似的结构,并使事情尽可能可预测(对您、维护和 VM 都有好处)来提供帮助。知道每个对象的属性,为这些属性设置类型,并在可能的时候从构造函数创建对象应该让您达到大多数可用的优化并拥有一些非常快速的代码。
来自Java,Javascript对象让我想起了Java中的HashMap。
Java脚本:
var myObject = {
firstName: "Foo",
lastName: "Bar",
email: "foo@bar.com"
};
Java:
HashMap<String, String> myHashMap = new HashMap<String, String>();
myHashMap.put("firstName", "Foo");
myHashMap.put("lastName", "Bar");
myHashMap.put("email", "foo@bar.com");
在JavaHashMap中,它使用键的hashcode()函数来确定用于存储和检索的桶位置(条目)。大多数时候,对于 put() 和 get() 等基本操作,性能是常数时间,直到发生哈希冲突,对于这些基本操作变为 O(n),因为它形成一个链表以存储条目冲突。
我的问题是:
- Java脚本如何存储对象?
- 操作的性能如何?
- 是否会像 Java 那样发生任何碰撞或其他会降低性能的情况
谢谢!
Javascript 看起来像是将内容存储在地图中,但通常情况并非如此。您可以访问对象的大多数属性,就好像它们是映射中的索引一样,并在运行时分配新属性,但支持代码比仅使用映射更快、更复杂。
没有什么要求 VM 不使用映射,但大多数尝试检测对象的结构并为该结构创建有效的内存表示。当程序 运行 时,这会导致大量优化(和取消优化),这是一个非常复杂的情况。
This blog post,在@Zirak 的问题评论中链接,对常见结构以及 VM 何时可以从结构切换到映射进行了很好的讨论。它通常看起来不可预测,但主要基于 VM 中的一组启发式方法以及它认为它已经看到了多少不同的对象。这在很大程度上与 return 值的属性(及其类型)有关,并且往往以每个函数(尤其是构造函数)为中心。
有一些问题和文章深入细节(但希望在没有大量背景的情况下仍然可以理解):
- Why is getting a member faster than calling hasOwnProperty?
- http://mrale.ph/blog/2013/08/14/hidden-classes-vs-jsperf.html(以及本博客的其余部分)
根据以上情况,性能差异很大。最坏的情况应该是映射访问,最好的情况是直接内存访问(甚至可能是 deref)。
有很多场景可能会影响性能,特别是考虑到 JITter 和 VM 如何在运行时创建和销毁隐藏的 类,因为它们会看到对象的新变体。突然遇到一个之前被认为是单态的对象的新变体会导致 VM 切换回不太理想的表示并停止将该对象视为内存中的结构,但围绕它的逻辑非常复杂而且很好-涵盖在 this blog post.
您可以通过确保从同一构造函数创建的对象往往具有非常相似的结构,并使事情尽可能可预测(对您、维护和 VM 都有好处)来提供帮助。知道每个对象的属性,为这些属性设置类型,并在可能的时候从构造函数创建对象应该让您达到大多数可用的优化并拥有一些非常快速的代码。