JavaScript数据类型和数据结构

编程语言都有内置的数据结构,但这些结构往往因语言而异。本文试图列出JavaScript中可用的内置数据结构及其属性。这些可以用于构建其他数据结构。

这个语言概述提供了常见数据类型的类似摘要,但与其他语言进行了更多比较。

动态和弱类型

JavaScript是一个动态语言动态类型。JavaScript中的变量不与任何特定的值类型直接关联,任何变量都可以分配(和重新分配)所有类型的值:

js型
设foo=42;//foo现在是一个数字foo=“bar”;//foo现在是一个字符串foo=真;//foo现在是一个布尔值

JavaScript也是一个弱类型的语言,这意味着当操作涉及不匹配的类型时,它允许隐式类型转换,而不是抛出类型错误。

js型
常量foo=42;//foo是一个数字常量结果=foo+“1”;//JavaScript将foo强制为字符串,因此它可以与其他操作数连接console.log(结果);//421

隐式强制非常方便,但当转换发生在预期之外的地方,或者在预期会发生在另一个方向(例如,字符串到数字而不是数字到字符串)时,可能会产生细微的错误。对于符号BigInts公司,JavaScript故意禁止某些隐式类型转换。

基本值

除以下类型外的所有类型对象定义不可变的在语言的最底层直接表示的值。我们将这些类型的值称为基本值.

所有基元类型,除了无效的,可以通过类型操作员。null类型收益“对象”,所以必须使用===空测试无效的.

所有基元类型,除了无效的未定义,具有相应的对象包装器类型,这些类型为使用原语值提供了有用的方法。例如编号对象提供了如下方法到指数()。当在基元值上访问属性时,JavaScript会自动将该值包装到相应的包装器对象中,并访问该对象上的属性。但是,访问上的属性无效的未定义抛出一个类型错误例外,这需要引入可选链接操作员。

类型 类型返回值 对象包装器
无效的 “对象” 不适用
未定义 “未定义” 不适用
布尔值 “布尔值” 布尔值
编号 “数字” 编号
BigInt公司 “bigint” BigInt公司
字符串 “字符串” 字符串
符号 “符号” 符号

对象包装类的参考页面包含关于每个类型可用的方法和属性的更多信息,以及对基本类型本身语义的详细描述。

Null类型

Null类型只包含一个值:无效的.

未定义的类型

未定义类型仅包含一个值:未定义.

从概念上讲,未定义表示缺少价值,同时无效的表示缺少对象(这也可能成为typeof null===“对象”). 语言通常默认为未定义当某物没有价值时:

  • 返回没有值的语句(回报;)隐式返回未定义.
  • 访问不存在的对象财产(对象不存在)收益未定义.
  • 未初始化的变量声明(设x;)隐式地将变量初始化为未定义.
  • 许多方法,例如Array.prototype.find()Map.prototype.get(),返回未定义找不到元素时。

无效的在核心语言中很少使用。最重要的地方是原型链-随后,与原型交互的方法,例如Object.getPrototypeOf(),对象.create()等,接受或返回无效的而不是未定义.

无效的是一个关键字,但是未定义是正常的标识符这恰巧是一项全球性财产。实际上,差异很小,因为未定义不应重新定义或隐藏。

布尔型

这个布尔值类型表示一个逻辑实体,由两个值组成:真的.

布尔值通常用于条件运算,包括三目操作符,如果…否则,虽然等。

数字类型

这个编号类型是双精度64位二进制格式IEEE 754值。它能够存储2之间的正浮点数-1074(数量。最小值(_V))和21023× (2 - 2-52) (数量。最大值(_V))以及相同大小的负浮点数,但它只能安全地存储范围为-(2)的整数53− 1) (数量。最小安全整数)至253− 1 (数量。最大安全整数). 在这个范围之外,JavaScript不能再安全地表示整数;它们将用双精度浮点近似表示。可以使用以下命令检查数字是否在安全整数范围内数字.isSafeInteger().

可代表范围外的值会自动转换:

+无限-无限行为类似于数学无穷大,但略有不同;看见数量。积极_不确定性数量。负E_无限了解详细信息。

“数字”类型只有一个具有多个表示形式的值:0表示为两者-0+0(其中0是的别名+0). 在实践中,不同表述之间几乎没有差异;例如,+0 === -0真的然而,当你被零除时,你会注意到这一点:

js型
console.log(42/+0);//无穷控制台.log(42/-0);//-无穷

NaN公司("N个其他 N个number“)是一种特殊的数值,通常在算术运算的结果无法表示为数字时会遇到。它也是JavaScript中唯一不等于自身的值。

虽然数字在概念上是一个“数学值”,并且总是隐式使用浮点编码,但JavaScript提供了定义的位运算。应用按位运算符时,数字首先转换为32位整数。

注:尽管按位运算符可以用于表示单个数字中的多个布尔值,使用位屏蔽,这通常被认为是一种不好的做法。JavaScript提供了其他方法来表示一组布尔值(如布尔值数组,或为命名属性指定布尔值的对象)。位屏蔽也会使代码更难阅读、理解和维护。

在非常受限的环境中可能有必要使用此类技术,例如当试图应对本地存储的限制时,或在极端情况下(例如当网络上的每个位都计数时)。只有当这是可以用来优化尺寸的最后一个措施时,才应该考虑这项技术。

BigInt类型

这个BigInt公司type是JavaScript中的数字原语,可以表示任意大小的整数。使用BigInts,您可以安全地存储和操作大整数,即使超出了安全整数限制(数量。最大安全整数)用于数字。

BigInt是通过附加n个到整数的末尾,或通过调用BigInt()功能。

此示例演示了递增数量。最大安全整数返回预期结果:

js型
//BigInt公司const x=BigInt(数字.MAX_SAFE_INTEGER);//9007199254740991年x+1n===x+2n;//错误,因为9007199254740992n和9007199244740993n不相等//编号数量。MAX_SAFE_INTEGER+1===数量。MAX_SAFE_INTEGER+2;//正确,因为两者都是9007199254740992

您可以使用大多数运算符来处理BigInt,包括+,*,-,**、和%-唯一被禁止的是>>>.BigInt不是严格相等到具有相同数学值的数字,但它是松散地所以。

BigInt值既不总是比数字更精确,也不总是不如数字精确,因为BigInts不能表示分数,但可以更准确地表示大整数。这两种类型都不需要另一种类型,并且它们不可相互替代。类型错误如果BigInt值与算术表达式中的正则数混合,或者如果隐式转换彼此之间。

字符串类型

这个字符串类型表示文本数据,并被编码为16位无符号整数值序列,表示UTF-16代码单元。字符串中的每个元素都占据字符串中的一个位置。第一个元素位于索引处0,下一个位于索引处1等等长度字符串中UTF-16代码单元的数量,可能与Unicode字符的实际数量不对应;请参阅字符串有关更多详细信息,请参见参考页。

JavaScript字符串是不可变的。这意味着一旦创建了字符串,就无法对其进行修改。字符串方法根据当前字符串的内容创建新字符串,例如:

小心“字符串输入”你的代码!

使用字符串来表示复杂数据可能很诱人。这样做会带来短期利益:

  • 使用串联很容易构建复杂字符串。
  • 字符串很容易调试(您看到的打印内容总是字符串中的内容)。
  • 字符串是许多API的公约数(输入字段,本地存储器值,获取()使用时的响应响应.text()等),并且只使用字符串可能很诱人。

使用约定,可以在字符串中表示任何数据结构。这并不是一个好主意。例如,使用分隔符,可以模拟列表(而JavaScript数组更合适)。不幸的是,当分隔符用于其中一个“list”元素时,列表将被破坏。可以选择转义字符等。所有这些都需要约定,并造成不必要的维护负担。

对文本数据使用字符串。表示复杂数据时,解析字符串,并使用适当的抽象。

符号类型

符号是一个独特的不可变的基本值,可以用作Object属性的键(参见下文)。在一些编程语言中,符号被称为“原子”。符号的目的是创建唯一的属性键,确保不会与其他代码的键冲突。

物体

在计算机科学中,对象是内存中的值,它可能由标识符。在JavaScript中,对象是唯一的可变的值。功能实际上,也是具有额外存在能力的对象可调用的.

属性

在JavaScript中,对象可以被视为属性的集合。使用对象文字语法,初始化一组有限的属性;然后可以添加和删除属性。对象属性等价于键值对。属性键可以是符号。当使用其他类型(例如数字)为对象编制索引时,这些值会隐式转换为字符串。属性值可以是任何类型的值,包括其他对象,这样可以构建复杂的数据结构。

有两种类型的对象属性:数据财产存取器财产。每个属性都有相应的属性。JavaScript引擎在内部访问每个属性,但您可以通过对象.defineProperty()或通读Object.getOwnPropertyDescriptor()。您可以阅读更多关于对象.defineProperty()第页。

Data属性

数据属性将键与值相关联。可以通过以下属性进行描述:

价值

由属性的get访问检索到的值。可以是任何JavaScript值。

可写的

一个布尔值,指示是否可以通过赋值更改属性。

可枚举的

一个布尔值,指示属性是否可以由用于。。。在里面循环。另请参见属性的可枚举性和所有权可枚举性如何与其他函数和语法交互。

可配置的

一个布尔值,指示属性是否可以删除、是否可以更改为访问器属性以及是否可以更改其属性。

访问器属性

将密钥与两个访问器函数之一相关联(得到设置)检索或存储值。

注:识别它的访问器很重要财产-非访问器方法。我们可以通过使用函数作为值来提供类似JavaScript对象类的访问器,但这不会使对象成为类。

访问器属性具有以下属性:

得到

使用空参数列表调用的函数,用于在执行get访问值时检索属性值。另请参见吸气剂。可能是未定义.

设置

使用包含指定值的参数调用的函数。每当试图更改指定属性时执行。另请参见设置器。可能是未定义.

可枚举的

一个布尔值,指示属性是否可以由用于。。。在里面循环。另请参见财产的可枚举性和所有权可枚举性如何与其他函数和语法交互。

可配置的

一个布尔值,指示属性是否可以删除、是否可以更改为数据属性以及是否可以更改其属性。

这个原型对象的指向另一个对象或指向无效的-它在概念上是对象的隐藏属性,通常表示为[[原型]]。对象的属性[[原型]]也可以在对象本身上访问。

对象是特殊的键值对,因此它们通常用作映射。然而,可能存在人体工程学、安全性和性能问题。使用地图用于存储任意数据。这个地图参考包含了更详细的讨论,讨论了普通对象和用于存储键值关联的映射之间的优缺点。

日期

表示日期时,最好的选择是使用内置日期JavaScript中的实用程序。

索引集合:数组和类型化数组

阵列是整数键属性和长度属性。

此外,数组继承自阵列原型,它提供了一些操作数组的方便方法。例如,索引()搜索数组中的值并push()将一个元素附加到数组中。这使得Arrays成为表示有序列表的理想候选。

类型化数组提供底层二进制数据缓冲区的类数组视图,并提供许多与数组对应项具有类似语义的方法。“类型化数组”是一个总括性术语,用于表示一系列数据结构,包括Int8阵列,Float32数组等。检查类型化数组第页了解更多信息。类型化数组通常与阵列缓冲区数据视图.

键控集合:贴图、集、弱贴图、弱集

这些数据结构将对象引用作为键。设置弱集表示唯一值的集合,而地图WeakMap(弱点地图)表示键值关联的集合。

你可以实施地图s和设置就是你自己。然而,由于对象无法进行比较(从<例如,“小于”),引擎也不公开其对象的哈希函数,查找性能必然是线性的。它们的本机实现(包括WeakMap(弱点地图)s) 可以具有近似对数到恒定时间的查找性能。

通常,要将数据绑定到DOM节点,可以直接在对象上设置属性,或使用数据-*属性。这有一个缺点,即在同一上下文中运行的任何脚本都可以使用数据。地图s和WeakMap(弱点地图)我们可以很容易地私下地将数据绑定到对象。

WeakMap(弱点地图)弱集只允许垃圾可收集值作为键,这些值可以是对象,也可以是非注册符号,即使密钥保留在集合中,也可以收集密钥。它们专门用于内存使用优化.

结构化数据:JSON

JSON格式(J型阿瓦S公司脚本O(运行)对象N个otation)是一种轻量级数据交换格式,源于JavaScript,但被许多编程语言使用。JSON构建了通用数据结构,可以在不同环境之间甚至跨语言传输。请参阅JSON格式了解更多详细信息。

标准库中的更多对象

JavaScript有一个内置对象的标准库。阅读参考以了解有关内置对象的更多信息。

类型强制

如上所述,JavaScript是一个弱类型的语言。这意味着您可以经常使用一种类型的值,而预期使用另一种类型,并且语言会将其转换为适合您的类型。为此,JavaScript定义了一些强制规则。

原始强制

这个原始强制process用于需要原语值的地方,但对实际类型没有强烈的偏好。这通常是在一串,一个,或aBigInt公司同样可以接受。例如:

  • 这个日期()构造函数,当它收到一个不是日期instance-strings表示日期字符串,而数字表示时间戳。
  • 这个+操作符-如果一个操作数是字符串,则执行字符串串联;否则,执行数值加法。
  • 这个==操作符-如果一个操作数是基元,而另一个是对象,则对象将转换为没有首选类型的基元值。

如果值已经是原语,则此操作不会进行任何转换。对象通过调用其[Symbol.to Primitive]()(与“默认”作为提示),值()、和toString()方法,按顺序。注意,原语转换调用值()之前toString(),这与数字强制但不同于字符串强制.

这个[Symbol.to Primitive]()方法(如果存在)必须返回原语-返回对象将导致类型错误。对于值()toString(),如果一个返回对象,则忽略返回值,而使用另一个的返回值;如果两者都不存在或都不返回原语,则类型错误被抛出。例如,在以下代码中:

js型
控制台.log({}+[]);//“[对象对象]”

两者都不是{}也不是[]有一个[Symbol.to Primitive]()方法。两者都有{}[]继承值()对象.原型.值,返回对象本身。由于返回值是一个对象,因此将忽略它。因此,toString()改为调用。{}.toString()收益“[对象对象]”,同时[].toString()收益"",因此结果是它们的串联:“[对象对象]”.

这个[Symbol.toPrimitive]()方法在转换为任何基元类型时始终优先。基本体转换通常与数字转换类似,因为值()优先调用;但是,具有自定义[Symbol.toPrimitive]()方法可以选择返回任何原语。日期符号对象是唯一覆盖[Symbol.to Primitive]()方法。日期原型[Symbol.toPrimitive]()治疗“默认”暗示好像是“字符串”,同时符号原型[Symbol.toPrimitive]()忽略提示并始终返回符号。

数字强制

有两种数字类型:编号BigInt公司。有时语言特别需要数字或BigInt(例如Array.prototype.slice(),其中索引必须是数字);其他时候,它可能会容忍其中之一,并根据操作数的类型执行不同的操作。有关不允许从其他类型进行隐式转换的严格强制过程,请参阅数字强制BigInt强制.

数字强制几乎与数字强制,但BigInt返回为-is,而不是导致类型错误。所有算术运算符都使用数字强制,因为数字和BigInt都重载了它们。唯一的例外是一元正号,它总是进行数字强制。

其他胁迫

除了Null、Undefined和Symbol之外,所有数据类型都有各自的强制过程。请参阅字符串强制,布尔强制、和对象强制了解更多详细信息。

您可能已经注意到,对象可以通过三条不同的路径转换为基本体:

在所有情况下,[Symbol.to Primitive](),如果存在,则必须是可调用的并返回基元,而的值到字符串如果它们不可调用或返回对象,则将被忽略。在过程结束时,如果成功,结果将被保证为原语。然后,根据上下文,生成的原语将受到进一步的强制。

另请参见