JavaScript VM如何实现Object属性访问?是Hashtable吗?

cio*_*Pep 23 javascript browser

JavaScript中的对象可以用作Hashtable(键必须是String)它是否像Hashtable一样表现良好的数据结构?

我的意思是,它是否在幕后实现为Hashtable?

更新:(1)我将HashMap更改为hashtable(2)我猜大多数浏览器都实现了相同的,如果不是为什么不呢?是否有任何要求如何在ECMAScript规范中实现它?

更新2:我理解,我只是想知道V8和Firefox JS VM如何实现Object.properties getters/setters?

Dud*_*lul 31

V8没有将对象属性访问实现为哈希表,它实际上以更好的方式实现它(性能明智)

那么它是怎样工作的?"V8不使用动态查找来访问属性.相反,V8动态地在后台创建隐藏类" - 这使得对属性的访问几乎与访问C++对象的属性一样快.

为什么?因为在固定类中,每个属性都可以在特定的固定偏移位置找到.

所以通常在V8中访问对象的属性比Hashtable快.

我不确定它在其他虚拟机上是如何工作的

可以在此处找到更多信息:https://developers.google.com/v8/design#prop_access

您还可以在这里阅读有关JS中Hashtable的更多信息:(我的博客)http://simplenotions.wordpress.com/2011/07/05/javascript-hashtable/

  • 新文档链接为https://developers.google.com/v8/design#prop_access (4认同)
  • 它怎么可能为一个可以接受运行时生成的任意键的对象创建一个静态类?当然它不可能在所有情况下都这样做。 (3认同)
  • V8 设计文档链接已损坏。这有什么想法吗? (2认同)
  • 最后一个链接不起作用,我认为这应该是新的:https://v8.dev/blog/fast-properties (2认同)

Jam*_*rgy 11

"我猜大多数浏览器实现它是相同的,如果不是为什么不呢?是否有任何要求如何在ECMAScript规范中实现它?"

我不是专家,但我想不出任何理由为什么语言规范会详细说明其功能必须如何在内部实现.这样的约束绝对没有目的,因为除了性能之外,它不会以任何方式影响语言的功能.

编辑 -尽管这两个downvotes,其实,这是绝对正确的,实际上是在ECMA-262规范的执行独立的专门desscribed 部分8.6.2规范的:

"这些表中的说明表示他们的行为对本地ECMAScript的对象,除非该文件的特定种类的原生的ECMAScript对象的说明.只要主机对象可以支持任何依赖于实现这些行为的内部属性,因为它是与特定一致本文件中陈述的主机对象限制 "

"除非另有说明,否则主机对象可以以任何方式实现这些内部方法;"

"hash"一词在整个ECMA-262规范中没有出现.

(原件,续)

例如,Internet Explorer 6.0和Google Chrome的V8中的Javascscript的实现几乎没有任何共同点,但(或多或少)都符合相同的规范.

如果您想知道特定的JavaScript解释器如何做某事,您应该专门研究该引擎.

Hashtables是创建交叉引用的有效方法.他们不是唯一的方式.例如,一些引擎可以针对小集合优化存储(对于哈希表的开销可能效率较低).

在这一天结束时,所有你需要知道的是,他们的工作.可能有更快的方法来创建的大型集查找表,使用AJAX,甚至在内存中.例如上看到有趣的讨论,这篇文章从约翰Reseig的博客有关使用特里数据结构.

但这既不是在这里也不是在那里.您是否使用此对象或本机JS对象的选择不应由有关JS如何实现对象的信息驱动.它应该仅通过性能比较来驱动:每种方法如何缩放.这是通过性能测试获得的信息,而不仅仅是了解JS引擎实现.

  • 我想这是因为问题是关于实际的实现("幕后").说这个规范不需要*一个特定的解决方案在这里是有限的帮助. (3认同)
  • 是的,性能考虑应该由实际数据驱动.但是,了解实施策略是一种非常有用的启发式方法,其确定起来非常便宜:它是基准测试中的一个伟大的,背面的第一步.你的帖子有很多有用的信息,但OP的问题仍然有效. (2认同)

Val*_*kov 5

大多数现代 JS 引擎使用非常相似的技术来加速对象属性访问。该技术基于所谓的隐藏类形状。了解这种优化如何编写高效的 JS 代码很重要。

JS 对象看起来像一个字典,那么为什么不使用一个来存储属性呢?哈希表的访问复杂度为 O(1),看起来是个不错的解决方案。实际上,最早的 JS 引擎已经以这种方式实现了对象。但在静态类型语言中,如 C++ 或 Java,类实例属性访问速度快如闪电。在这样的语言中,类实例只是一段内存,每个属性都有自己的常量偏移量,因此要获取属性值,我们只需要获取实例指针并为其添加偏移量。换句话说,在编译时,像这样的表达式point.x只是被它在内存中的地址替换。

也许我们可以在 JS 中实现一些类似的技术?但是如何?我们来看一个简单的JS函数:

function getX(point) {
  return point.x;
}
Run Code Online (Sandbox Code Playgroud)

如何获得point.x价值?这里的第一个问题是我们没有描述point. 但是我们可以计算一个,这就是现代 JS 引擎所做的。大多数 JS 对象在运行时都有一个绑定到对象的形状。形状描述了对象的属性以及这些属性值的存储位置。它与类定义在 C++ 或 Java 中描述类的方式非常相似。这是一个相当大的问题,一个物体的Shape是如何计算的,这里就不赘述了。我推荐这篇文章,其中包含对一般形状的很好解释,并且这篇文章这解释了这些东西是如何在 V8 中实现的。关于形状你应该知道的最重要的事情是,所有具有相同属性的对象以相同的顺序添加将具有相同的形状。很少有例外,例如如果一个对象有很多经常更改的属性,或者如果您使用delete运算符删除一些对象属性,则该对象将切换到字典模式并且不会有形状。

现在,让我们想象这个point对象有一个属性值数组,我们有一个形状附加到它上面,它描述了x这个属性数组中的值的存储位置。但是还有另一个问题——我们可以将任何对象传递给函数,甚至不需要对象具有x属性。这个问题是通过称为内联缓存的技术解决的。很简单,getX()第一次执行时,它记住了点的形状和x查找的结果。第二次调用该函数时,它会将点的形状与前一个进行比较。如果形状匹配不需要查找,我们可以取之前的查找结果。

主要结论是所有描述相同事物的对象都应该具有相同的形状,即它们应该具有以相同顺序添加的相同属性集。它还解释了为什么最好始终初始化对象属性,即使它们是undefined默认设置,这里是问题的一个很好的解释。

相关资源: