繁体   English   中英

Javascript 中的对象 vs 数组就像 Python 的字典 vs 列表?

[英]Object vs Arrays in Javascript is as Python's Dictionaries vs Lists?

我知道在 python 中我可以使用列表来进行快速排序和字典以便更快地搜索(因为不可变对象可以散列)。 javascript 也是这样吗? 经过大量搜索,我还没有看到任何有关 javascript 中数据类型性能的信息。

是的。 “Javascript 中的对象 vs 数组就像 Python 的字典 vs 列表”。 性能优劣也是一样的。 如果数字索引适用于任务,则列表效率更高,而字典对于必须通过字符串访问的长列表效率更高。

var dict = {};
dict['apple'] = "a sweet edible fruit";
dict['boy'] = "a young male human";

var list = [];
list.push("apples");
list.push("oranges");
list.push("pears");

我一直在寻找可以回答这个问题的一些参考书目和其他来源。 我知道这不是最好的答案,但让我尝试一个涉及一些概念的答案,这些概念使我们能够讨论这个主题。

Javascript 和继承

尽管它可能表明 javascript 中的数组和对象类似于列表和字典,但它们是不同的,因为每种语言都以不同的方式编写,具有不同的基本哲学、概念和目的。

就 Javascript 而言,似乎 Arryas 和 Objects 都更像是哈希表。 与直觉相反,数组只是 javascript 的另一种内置对象。 事实上,正如他们在ECMAScript 规范 6.1.7 中所说

对象类型

对象在逻辑上是属性的集合。 每个属性要么是数据属性,要么是访问器属性:

数据属性将键值与 ECMAScript 语言值和一组布尔属性相关联。 访问器属性将键值与一个或两个访问器函数以及一组布尔属性相关联。 访问器函数用于存储或检索与属性关联的 ECMAScript 语言值。 使用键值标识属性。 属性键值是 ECMAScript 字符串值或符号值。 所有字符串和符号值,包括空字符串,都作为属性键有效。 属性名称是一个属性键,它是一个字符串值。

整数索引是一个字符串值属性键,它是一个规范的数字字符串(见 7.1.16),其数值为 +0 或一个 ≤ 253 - 1 的正整数。数组索引是一个整数索引,其数值为 i在 +0 ≤ i < 232 - 1 的范围内。

属性键用于访问属性及其值。 属性有两种访问方式:get 和 set,分别对应取值和赋值。 通过 get 和 set 访问可访问的属性包括作为对象直接部分的自身属性和由另一个关联对象通过属性继承关系提供的继承属性。 继承的属性可以是关联对象的自己的或继承的属性。 对象的每个自己的属性都必须有一个键值,该键值与该对象的其他自己的属性的键值不同。

而且, 关于数组,它指定:

22.1数组对象

数组对象是特殊对象,它们对特定类别的属性名称进行特殊处理。

按照上面的逻辑,正如规范中所说的那样,语言被认为是这样的:javascript 中的所有类型都扩展了一个全局对象,然后添加了新的方法和属性以具有不同的行为。

内存管理

语言规范与它们必须如何在实际运行时环境中实现之间存在差距。 尽管每个实现都有自己的逻辑,但似乎大多数都有相似之处。

正如本文所解释的

大多数 JavaScript 解释器使用类似字典的结构(基于哈希函数)来存储对象属性值在内存中的位置。 这种结构使得在 JavaScript 中检索属性的值比在非动态编程语言(如 Java 或 C#)中检索的计算成本更高。 在Java中,所有的对象属性在编译前都是由一个固定的对象布局决定的,不能在运行时动态添加或删除(好吧,C#有动态类型,这是另一个话题)。 因此,属性值(或指向这些属性的指针)可以作为连续缓冲区存储在内存中,每个值之间具有固定的偏移量。 可以根据属性类型轻松确定偏移量的长度,而这在 JavaScript 中是不可能的,因为属性类型可以在运行时更改。

由于这使得 javascript 效率低下,工程师不得不提出一些聪明的解决方法来解决这个问题。 这篇另一篇文章之后

如果您访问一个属性,例如 object.y,JavaScript 引擎会在 JSObject 中查找键 'y',然后加载相应的属性属性,最后返回 [[Value]]。

但是这些属性属性存储在内存中的什么地方呢? 我们应该将它们存储为 JSObject 的一部分吗? 如果我们假设我们稍后会看到更多具有这种形状的对象,那么将包含属性名称和属性的完整字典存储在 JSObject 本身上是很浪费的,因为所有具有相同形状的对象的属性名称都是重复的。 这是很多重复和不必要的内存使用。 作为优化,引擎单独存储对象的形状。

此 Shape 包含所有属性名称和属性,除了它们的 [[Value]]s。 相反,Shape 包含 JSObject 内部值的偏移量,以便 JavaScript 引擎知道在哪里可以找到这些值。 每个具有相同形状的 JSObject 都指向这个 Shape 实例。 现在每个 JSObject 只需要存储这个对象唯一的值。

当我们有多个对象时,好处就很明显了。 不管有多少个物体,只要它们的形状相同,我们只需要存储一次形状和属性信息!

所有 JavaScript 引擎都使用形状作为优化,但它们并不都称为形状:

  • 学术论文称它们为隐藏类(混淆了 JavaScript 类)
  • V8 称它们为 Maps(与 JavaScript Maps 混淆)
  • Chakra 称它们为类型(混淆了 JavaScript 的动态类型和 typeof)
  • JavaScriptCore 称它们为结构 *SpiderMonkey 称它们为形状

Python

数组

Python 使用不同的方法来实现列表,看起来列表更像是一些动态数组,而不是您可以在 C 中找到的实际数组,但它们仍然专注于节省时间和运行时的复杂性空间。 正如 PyDocs 引用的这个 FAQ 所说

Python 的列表对象实际上是变长数组,而不是 Lisp 风格的链表。 该实现使用对其他对象的连续引用数组,并在列表头结构中保留指向该数组的指针和该数组的长度。

这使得索引列表 (L[i]) 成为一种操作,其成本与列表的大小或索引的值无关。

当追加或插入项目时,引用数组的大小会被调整。 应用了一些技巧来提高重复附加项目的性能; 当数组必须增长时,会分配一些额外的空间,因此接下来的几次不需要实际调整大小。

与 javascript 一样,Python 的列表不需要是同类的,因此它们不是其他“强类型”数据结构的实际实现,这些结构必须只包含相同的实体,例如整数、字符串等。

与 javascript 相同,实际实现的语言规范是两个独立的东西。 根据您是否使用 Cpython、Jython、IronPython 等,在将 Python 解释为机器代码的过程中,内存管理和在幕后运行的实际函数将产生不同的东西。

我知道这不是最好的来源,但正如我在 Quora 中所讨论的

与其名称所暗示的相反,Python 列表实际上是数组(...)。 具体来说,它们是具有指数超额分配的动态数组,这使得如下代码具有线性复杂度:

 lst = [] for i in xrange(0, 100000): lst.append(i)

Jython 和 IronPython 等替代实现似乎使用其底层语言(分别是 Java 和 C#)提供的任何本机动态数组类,因此它们具有相同的性能特征(确切的底层类似乎是 Jython 的 ArrayList 和 IronPython 的 C# List)。

(...) 数组在技术上存储指针而不是对象本身,这允许数组仅包含特定大小的元素。 在底层实现中到处都有指针是动态类型语言的一个共同特征,实际上任何试图假装它没有指针的语言都是如此。

字典

正如官方文档在他们的“历史和设计常见问题解答”中所说的那样

CPython 的字典实现为可调整大小的哈希表。 与 B 树相比,这在大多数情况下为查找(迄今为止最常见的操作)提供了更好的性能,并且实现更简单。

字典的工作原理是使用 hash() 内置函数为字典中存储的每个键计算哈希码。 哈希码因密钥而异; 例如,“Python”散列为 -539294296,而“python”,一个相差一位的字符串,散列为 1142331976。然后使用散列码计算内部数组中将存储值的位置。 假设您存储的键都具有不同的散列值,这意味着字典需要恒定的时间——在计算机科学符号中为 O(1)——来检索一个键。 这也意味着不维护键的排序顺序,并且像 .keys() 和 .items() 那样遍历数组将以某种任意混乱的顺序输出字典的内容。

结论中

关于语言有两个不同的方面:一个涉及它应该如何工作,以及它的语法、语义、逻辑和哲学。 另一方面,您可以在特定的运行时、解释器或编译器中实际实现该语言。 这样,虽然(理论上)您拥有一个 Python 或一个 Javascript,但您可以拥有 CPython、IronPython Jython 等; 另一方面,你有 SpiderMonkey、V8 等。

但是参考每个运行时如何实现数组/列表和对象/字典的语言特性以及它们的相似性,似乎Javascript选择了基于原型的继承模型,使everithing成为一种对象; 所以对象和字典都更像是一个哈希表而不是一个实际的数组。 另一方面,Python 在数据结构方面有更多风格,包括它们的库和解释器如何处理它们,利用数组或动态数组使 Pyton 列表栩栩如生,并使用哈希表字典,使它们更类似于 javascript 中的对象。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM