aboutsummaryrefslogtreecommitdiff
path: root/files/zh-cn/web/javascript/data_structures
diff options
context:
space:
mode:
Diffstat (limited to 'files/zh-cn/web/javascript/data_structures')
-rw-r--r--files/zh-cn/web/javascript/data_structures/index.html321
1 files changed, 321 insertions, 0 deletions
diff --git a/files/zh-cn/web/javascript/data_structures/index.html b/files/zh-cn/web/javascript/data_structures/index.html
new file mode 100644
index 0000000000..5b3e069800
--- /dev/null
+++ b/files/zh-cn/web/javascript/data_structures/index.html
@@ -0,0 +1,321 @@
+---
+title: JavaScript 数据类型和数据结构
+slug: Web/JavaScript/Data_structures
+tags:
+ - JavaScript
+ - 初学者
+ - 数据结构
+ - 类型
+translation_of: Web/JavaScript/Data_structures
+---
+<div>{{jsSidebar("More")}}</div>
+
+<p>编程语言都具有内建的数据结构,但各种编程语言的数据结构常有不同之处。本文试图列出 JavaScript 语言中内建的数据结构及其属性,它们可以用来构建其他的数据结构;同时尽可能地描述与其他语言的不同之处。</p>
+
+<h2 id="动态类型">动态类型</h2>
+
+<p>JavaScript 是一种<strong>弱类型</strong>或者说<strong>动态</strong>语言。这意味着你不用提前声明变量的类型,在程序运行过程中,类型会被自动确定。这也意味着你可以使用同一个变量保存不同类型的数据:</p>
+
+<pre class="brush: js notranslate">var foo = 42; // foo is a Number now
+foo = "bar"; // foo is a String now
+foo = true; // foo is a Boolean now
+</pre>
+
+<h2 id="数据类型">数据类型</h2>
+
+<p>最新的 ECMAScript 标准定义了 9 种数据类型:</p>
+
+<ul>
+ <li>6 种{{Glossary("Primitive", "原始类型")}},使用 {{Glossary("typeof")}} 运算符检查:
+ <ul>
+ <li>{{Glossary("undefined")}}:<code>typeof instance === "undefined"</code></li>
+ <li>{{Glossary("Boolean")}}:<code>typeof instance === "boolean"</code></li>
+ <li>{{Glossary("Number")}}:<code>typeof instance === "number"</code></li>
+ <li>{{Glossary("String")}}:<code>typeof instance === "string</code></li>
+ <li>{{Glossary("BigInt")}}:<code>typeof instance === "bigint"</code></li>
+ <li>{{Glossary("Symbol")}} :<code>typeof instance === "symbol"</code></li>
+ </ul>
+ </li>
+ <li>{{Glossary("null")}}:<code>typeof instance === "object"</code>。</li>
+ <li>{{Glossary("Object")}}:<code>typeof instance === "object"</code>。任何 {{Glossary("constructed")}} 对象实例的特殊非数据结构类型,也用做数据结构:new {{Glossary("Object")}},new {{Glossary("Array")}},new {{Glossary("Map")}},new {{Glossary("Set")}},new {{Glossary("WeakMap")}},new {{Glossary("WeakSet")}},new {{Glossary("Date")}},和几乎所有通过 {{Glossary("new keyword")}} 创建的东西。</li>
+ <li>{{Glossary("Function")}}:非数据结构,尽管 typeof 操作的结果是:<code>typeof instance === "function"</code>。这个结果是为 Function 的一个特殊缩写,尽管每个 Function 构造器都由 Object 构造器派生。</li>
+</ul>
+
+<p>记住 <code>typeof</code> 操作符的唯一目的就是检查数据类型,如果我们希望检查任何从 Object 派生出来的结构类型,使用 <code>typeof</code> 是不起作用的,因为总是会得到 <code>"object"</code>。检查 Object 种类的合适方式是使用 {{Glossary("instanceof")}} 关键字。但即使这样也存在误差。</p>
+
+<h2 id="原始值_primitive_values">原始值( primitive values )</h2>
+
+<p>除 Object 以外的所有类型都是不可变的(值本身无法被改变)。例如,与 C 语言不同,JavaScript 中字符串是不可变的(译注:如,JavaScript 中对字符串的操作一定返回了一个新字符串,原始字符串并没有被改变)。我们称这些类型的值为“原始值”。</p>
+
+<h3 id="布尔类型">布尔类型</h3>
+
+<p>布尔表示一个逻辑实体,可以有两个值:<code>true</code> 和 <code>false</code>。</p>
+
+<h3 id="Null_类型">Null 类型</h3>
+
+<p>Null 类型只有一个值: <code>null</code>,更多详情可查看 {{jsxref("null")}} 和 {{Glossary("Null")}} 。</p>
+
+<h3 id="Undefined_类型">Undefined 类型</h3>
+
+<p>一个没有被赋值的变量会有个默认值 <code>undefined</code>,更多详情可查看 {{jsxref("undefined")}} 和 {{Glossary("Undefined")}}。</p>
+
+<h3 id="数字类型">数字类型</h3>
+
+<p>根据 ECMAScript 标准,JavaScript 中只有一种数字类型:基于 IEEE 754 标准的双精度 64 位二进制格式的值(-(2<sup>53</sup> -1) 到 2<sup>53</sup> -1)。<strong>它并没有为整数给出一种特定的类型</strong>。除了能够表示浮点数外,还有一些带符号的值:<code>+Infinity</code>,<code>-Infinity</code> 和 <code>NaN</code> (非数值,Not-a-Number)。</p>
+
+<p>要检查值是否大于或小于 <code>+/-Infinity</code>,你可以使用常量 {{jsxref("Number.MAX_VALUE")}} 和 {{jsxref("Number.MIN_VALUE")}}。另外在 ECMAScript 6 中,你也可以通过 {{jsxref("Number.isSafeInteger()")}} 方法还有 {{jsxref("Number.MAX_SAFE_INTEGER")}} 和 {{jsxref("Number.MIN_SAFE_INTEGER")}} 来检查值是否在双精度浮点数的取值范围内。 超出这个范围,JavaScript 中的数字不再安全了,也就是只有 second mathematical interger 可以在 JavaScript 数字类型中正确表现。</p>
+
+<p>数字类型中只有一个整数有两种表示方法: 0 可表示为 -0 和 +0("0" 是 +0 的简写)。 在实践中,这也几乎没有影响。 例如 <code>+0 === -0</code> 为真。 但是,你可能要注意除以0的时候:</p>
+
+<pre class="brush: js notranslate">42 / +0; // Infinity
+42 / -0; // -Infinity
+</pre>
+
+<p>尽管一个数字常常仅代表它本身的值,但JavaScript提供了一些<a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators" title="en/JavaScript/Reference/Operators/Bitwise_Operators">位运算符</a>。 这些位运算符和一个单一数字通过位操作可以用来表现一些布尔值。然而自从 JavaScript 提供其他的方式来表示一组布尔值(如一个布尔值数组或一个布尔值分配给命名属性的对象)后,这种方式通常被认为是不好的。位操作也容易使代码难以阅读,理解和维护, 在一些非常受限的情况下,可能需要用到这些技术,比如试图应付本地存储的存储限制。 位操作只应该是用来优化尺寸的最后选择。</p>
+
+<h3 id="BigInt_类型">BigInt 类型</h3>
+
+<p>{{jsxref("BigInt")}}类型是 JavaScript 中的一个基础的数值类型,可以用任意精度表示整数。使用 BigInt,您可以安全地存储和操作大整数,甚至可以超过数字的安全整数限制。BigInt是通过在整数末尾附加 <code>n </code>或调用构造函数来创建的。</p>
+
+<p>通过使用常量{{jsxref("Number.MAX_SAFE_INTEGER")}},您可以获得可以用数字递增的最安全的值。通过引入 BigInt,您可以操作超过{{jsxref("Number.MAX_SAFE_INTEGER")}}的数字。您可以在下面的示例中观察到这一点,其中递增{{jsxref("Number.MAX_SAFE_INTEGER")}}会返回预期的结果:</p>
+
+<pre class="notranslate"><code>&gt; const x = 2n ** 53n;
+9007199254740992n
+&gt; const y = x + 1n;
+9007199254740993n</code>
+</pre>
+
+<p>可以对<code>BigInt</code>使用运算符<code>+<font face="Arial, x-locale-body, sans-serif"><span style="background-color: #ffffff;">、</span></font></code><code>*<font face="Arial, x-locale-body, sans-serif"><span style="background-color: #ffffff;">、</span></font></code><code>-<font face="Arial, x-locale-body, sans-serif"><span style="background-color: #ffffff;">、</span></font></code><code>**</code>和<code>%</code>,就像对数字一样。BigInt 严格来说并不等于一个数字,但它是松散的。</p>
+
+<p>在将<code>BigInt</code>转换为<code>Boolean</code>时,它的行为类似于一个数字:<code>if<font face="Arial, x-locale-body, sans-serif"><span style="background-color: #ffffff;">、</span></font></code><code>||<font face="Arial, x-locale-body, sans-serif"><span style="background-color: #ffffff;">、</span></font></code><code>&amp;&amp;<font face="Arial, x-locale-body, sans-serif"><span style="background-color: #ffffff;">、</span></font></code><code>Boolean<font face="Arial, x-locale-body, sans-serif"><span style="background-color: #ffffff;"> 和</span></font></code><code>!。</code></p>
+
+<p><code>BigInt</code>不能与数字互换操作。否则,将抛出{{jsxref("TypeError")}}。</p>
+
+<h3 id="字符串类型">字符串类型</h3>
+
+<p>JavaScript的字符串类型用于表示文本数据。它是一组16位的无符号整数值的“元素”。在字符串中的每个元素占据了字符串的位置。第一个元素的索引为0,下一个是索引1,依此类推。字符串的长度是它的元素的数量。</p>
+
+<p>不同于类 C 语言,JavaScript 字符串是不可更改的。这意味着字符串一旦被创建,就不能被修改。但是,可以基于对原始字符串的操作来创建新的字符串。例如:</p>
+
+<ul>
+ <li>获取一个字符串的子串可通过选择个别字母或者使用 {{jsxref("String.substr()")}}.</li>
+ <li>两个字符串的连接使用连接操作符 (<code>+</code>) 或者 {{jsxref("String.concat()")}}.</li>
+</ul>
+
+<h4 id="注意代码中的“字符串类型”!">注意代码中的“字符串类型”!</h4>
+
+<p>可以使用字符串来表达复杂的数据。以下是一些很好的性质:</p>
+
+<ul>
+ <li>容易连接构造复杂的字串符</li>
+ <li>字符串容易被调试(你看到的往往在字符串里)</li>
+ <li>字符串通常是许多APIs的常见标准 (<a href="/en/DOM/HTMLInputElement" title="HTMLInputElement">input fields</a>, <a href="/en/Storage" title="Storage">local storage</a> values, {{ domxref("XMLHttpRequest") }}当使用<code>responseText等</code>的时候回应) 而且他只能与字符串一同使用。</li>
+</ul>
+
+<p>使用约定,字符串一般可以用来表达任何数据结构。这不是一个好主意。例如,使用一个分隔符,可以模拟一个列表(而 JavaScript 数组可能更适合)。不幸的是,当分隔符用于列表中的元素时,列表就会被破坏。 可以选择转义字符,等等。所有这些都需要约定,并造成不必要的维护负担。</p>
+
+<p>表达文本数据和符号数据时候推荐使用字符串。当表达复杂的数据时,使用字符串解析和适当的缩写。</p>
+
+<h3 id="符号类型">符号类型</h3>
+
+<p>符号(Symbols)是ECMAScript 第6版新定义的。符号类型是唯一的并且是不可修改的, 并且也可以用来作为Object的key的值(如下). 在某些语言当中也有类似的原子类型(Atoms). 你也可以认为为它们是C里面的枚举类型. 更多细节请看 {{Glossary("Symbol")}} 和 {{jsxref("Symbol")}} 。</p>
+
+<h2 id="对象">对象</h2>
+
+<p>在计算机科学中, 对象是指内存中的可以被 {{Glossary("Identifier", "标识符")}}引用的一块区域.</p>
+
+<h3 id="属性">属性</h3>
+
+<p>在 Javascript 里,对象可以被看作是一组属性的集合。用<a href="/en/JavaScript/Guide/Values,_variables,_and_literals#Object_literals">对象字面量语法</a>来定义一个对象时,会自动初始化一组属性。(也就是说,你定义一个var a = "Hello",那么a本身就会有a.substring这个方法,以及a.length这个属性,以及其它;如果你定义了一个对象,var a = {},那么a就会自动有a.hasOwnProperty及a.constructor等属性和方法。)而后,这些属性还可以被增减。属性的值可以是任意类型,包括具有复杂数据结构的对象。属性使用键来标识,它的键值可以是一个字符串或者符号值(Symbol)。</p>
+
+<p>ECMAScript定义的对象中有两种属性:数据属性和访问器属性。</p>
+
+<h4 id="数据属性">数据属性</h4>
+
+<p>数据属性是键值对,并且每个数据属性拥有下列特性:</p>
+
+<p><strong>数据属性的特性(<span style="line-height: 1.5;">Attributes of a data property)</span></strong></p>
+
+<table class="standard-table">
+ <tbody>
+ <tr>
+ <th>特性</th>
+ <th>数据类型</th>
+ <th>描述</th>
+ <th>默认值</th>
+ </tr>
+ <tr>
+ <td>[[Value]]</td>
+ <td>任何Javascript类型</td>
+ <td>包含这个属性的数据值。</td>
+ <td>undefined</td>
+ </tr>
+ <tr>
+ <td>[[Writable]]</td>
+ <td>Boolean</td>
+ <td>如果该值为 <code>false,</code>则该属性的 [[Value]] 特性 不能被改变。</td>
+ <td>false</td>
+ </tr>
+ <tr>
+ <td>[[Enumerable]]</td>
+ <td>Boolean</td>
+ <td>如果该值为 <code>true,</code>则该属性可以用 <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...in">for...in</a> 循环来枚举。</td>
+ <td>false</td>
+ </tr>
+ <tr>
+ <td>[[Configurable]]</td>
+ <td>Boolean</td>
+ <td>如果该值为 <code>false,</code>则该属性不能被删除,并且 除了 [[Value]] 和 [[Writable]] 以外的特性都不能被改变。</td>
+ <td>false</td>
+ </tr>
+ </tbody>
+</table>
+
+<table class=" standard-table">
+ <caption>过时的属性(在ECMAScript 3定义的, 在ECMAScript 5被重命名)</caption>
+ <tbody>
+ <tr>
+ <th>属性</th>
+ <th>类型</th>
+ <th>描述</th>
+ </tr>
+ <tr>
+ <td>Read-only</td>
+ <td>Boolean</td>
+ <td>ES5 [[Writable]] 属性的反状态(Reversed state)</td>
+ </tr>
+ <tr>
+ <td>DontEnum</td>
+ <td>Boolean</td>
+ <td>ES5 [[Enumerable]]  属性的反状态</td>
+ </tr>
+ <tr>
+ <td>DontDelete</td>
+ <td>Boolean</td>
+ <td>ES5 [[Configurable]] 属性的反状态</td>
+ </tr>
+ </tbody>
+</table>
+
+<h4 id="访问器属性">访问器属性</h4>
+
+<p>访问器属性有一个或两个访问器函数 (get 和 set) 来存取数值,并且有以下特性:</p>
+
+<table class="standard-table">
+ <caption>一个访问器属性的特性</caption>
+ <tbody>
+ <tr>
+ <th>特性</th>
+ <th>类型</th>
+ <th>描述</th>
+ <th>默认值</th>
+ </tr>
+ <tr>
+ <td>[[Get]]</td>
+ <td>函数对象或者 undefined</td>
+ <td>该函数使用一个空的参数列表,能够在有权访问的情况下读取属性值。另见 <code><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/get">get</a>。</code></td>
+ <td>undefined</td>
+ </tr>
+ <tr>
+ <td>[[Set]]</td>
+ <td>函数对象或者 undefined</td>
+ <td>该函数有一个参数,用来写入属性值,另见 <code><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/set">set</a>。</code></td>
+ <td>undefined</td>
+ </tr>
+ <tr>
+ <td>[[Enumerable]]</td>
+ <td>Boolean</td>
+ <td>如果该值为 <code>true,则该属性可以用</code> <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...in">for...in</a> 循环来枚举。</td>
+ <td>false</td>
+ </tr>
+ <tr>
+ <td>[[Configurable]]</td>
+ <td>Boolean</td>
+ <td>如果该值为 <code>false,则该属性不能被删除,并且不能被转变成一个数据属性。</code></td>
+ <td>false</td>
+ </tr>
+ </tbody>
+</table>
+
+<div class="note">
+<p>注意:这些特性只有 JavaScript 引擎才用到,因此你不能直接访问它们。所以特性被放在两对方括号中,而不是一对。</p>
+</div>
+
+<h3 id="标准的_对象_和函数">"标准的" 对象, 和函数</h3>
+
+<p>一个 Javascript 对象就是键和值之间的映射.。键是一个字符串(或者 {{jsxref("Symbol")}}) ,值可以是任意类型的值。 这使得对象非常符合 <a class="external" href="http://en.wikipedia.org/wiki/Hash_table">哈希表</a>。</p>
+
+<p>函数是一个附带可被调用功能的常规对象。</p>
+
+<h3 id="日期">日期</h3>
+
+<p>当你想要显示日期时,毋庸置疑,使用内建的 <a href="/en/JavaScript/Reference/Global_Objects/Date">Date</a> 对象。</p>
+
+<h3 id="有序集_数组和类型数组">有序集: 数组和类型数组</h3>
+
+<p><a href="https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array" title="Array">数组</a>是一种使用整数作为键(integer-key-ed)属性和长度(length)属性之间关联的常规对象。此外,数组对象还继承了 Array.prototype 的一些操作数组的便捷方法。例如, <code><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf" title="en/JavaScript/Reference/Global_Objects/Array/indexOf">indexOf</a></code> (搜索数组中的一个值) or <code><a href="https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/push" title="en/JavaScript/Reference/Global_Objects/Array/push">push</a></code> (向数组中添加一个元素),等等。 这使得数组是表示列表或集合的最优选择。</p>
+
+<p><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Typed_arrays">类型数组(Typed Arrays)</a>是ECMAScript Edition 6中新定义的 JavaScript 内建对象,提供了一个基本的二进制数据缓冲区的类数组视图。下面的表格能帮助你找到对等的 C 语言数据类型:</p>
+
+<p>{{page("/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray", "TypedArray_objects", "", 0, 3)}}</p>
+
+<h3 id="键控集_Maps_Sets_WeakMaps_WeakSets">键控集: Maps, Sets, WeakMaps, WeakSets</h3>
+
+<p>这些数据结构把对象的引用当作键,其在ECMAScript第6版中有介绍。当 {{jsxref("Map")}} 和 {{jsxref("WeakMap")}} 把一个值和对象关联起来的时候, {{jsxref("Set")}} 和 {{jsxref("WeakSet")}} 表示一组对象。 Map和WeakMaps之间的差别在于,在前者中,对象键是可枚举的。这允许垃圾收集器优化后面的枚举(This allows garbage collection optimizations in the latter case)。</p>
+
+<p>在纯ECMAScript 5下可以实现Maps和Sets。然而,因为对象并不能进行比较(就对象“小于”示例来讲),所以查询必定是线性的。他们本地实现(包括WeakMaps)查询所花费的时间可能是对数增长。</p>
+
+<p>通常,可以通过直接在对象上设置属性或着使用data-*属性,来绑定数据到DOM节点。然而缺陷是在任何的脚本里,数据都运行在同样的上下文中。Maps和WeakMaps方便将数据私密的绑定到一个对象。 </p>
+
+<h3 id="结构化数据_JSON">结构化数据: JSON</h3>
+
+<p>JSON (JavaScript Object Notation) 是一种轻量级的数据交换格式,来源于 JavaScript 同时也被多种语言所使用。 JSON 用于构建通用的数据结构。参见 {{Glossary("JSON")}} 以及 {{jsxref("JSON")}} 了解更多。</p>
+
+<h3 id="标准库中更多的对象">标准库中更多的对象</h3>
+
+<p>JavaScript 有一个内置对象的标准库。请查看<a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects">参考</a>来了解更多对象。</p>
+
+<h2 id="使用_typeof_操作符判断对象类型">使用 typeof 操作符判断对象类型</h2>
+
+<p>typeof 运算符可以帮助你查询变量的类型。要了解更多细节和注意事项请阅读<a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/typeof">参考页</a>。</p>
+
+<h2 id="规范">规范</h2>
+
+<table class=" standard-table">
+ <tbody>
+ <tr>
+ <th scope="col">规范</th>
+ <th scope="col">状态</th>
+ <th scope="col">注释</th>
+ </tr>
+ <tr>
+ <td>{{SpecName('ES1')}}</td>
+ <td>{{Spec2('ES1')}}</td>
+ <td>初始定义</td>
+ </tr>
+ <tr>
+ <td>{{SpecName('ES5.1', '#sec-8', 'Types')}}</td>
+ <td>{{Spec2('ES5.1')}}</td>
+ <td></td>
+ </tr>
+ <tr>
+ <td>{{SpecName('ES2015', '#sec-ecmascript-data-types-and-values', 'ECMAScript Data Types and Values')}}</td>
+ <td>{{Spec2('ES2015')}}</td>
+ <td>
+ <p>Added Symbol.</p>
+ </td>
+ </tr>
+ <tr>
+ <td>{{SpecName('ESDraft', '#sec-ecmascript-data-types-and-values', 'ECMAScript Data Types and Values')}}</td>
+ <td>{{Spec2('ESDraft')}}</td>
+ <td></td>
+ </tr>
+ </tbody>
+</table>
+
+<h2 id="参考资料">参考资料</h2>
+
+<ul>
+ <li><a class="link-https" href="https://github.com/nzakas/computer-science-in-javascript/">Nicholas Zakas collection of common data structure and common algorithms in JavaScript.</a></li>
+ <li><a href="https://github.com/monmohan/DataStructures_In_Javascript" title="https://github.com/monmohan/DataStructures_In_Javascript">Search Tre(i)es implemented in JavaScript</a></li>
+</ul>