aboutsummaryrefslogtreecommitdiff
path: root/files/zh-cn/web/javascript/guide
diff options
context:
space:
mode:
authorPeter Bengtsson <mail@peterbe.com>2020-12-08 14:40:17 -0500
committerPeter Bengtsson <mail@peterbe.com>2020-12-08 14:40:17 -0500
commit33058f2b292b3a581333bdfb21b8f671898c5060 (patch)
tree51c3e392513ec574331b2d3f85c394445ea803c6 /files/zh-cn/web/javascript/guide
parent8b66d724f7caf0157093fb09cfec8fbd0c6ad50a (diff)
downloadtranslated-content-33058f2b292b3a581333bdfb21b8f671898c5060.tar.gz
translated-content-33058f2b292b3a581333bdfb21b8f671898c5060.tar.bz2
translated-content-33058f2b292b3a581333bdfb21b8f671898c5060.zip
initial commit
Diffstat (limited to 'files/zh-cn/web/javascript/guide')
-rw-r--r--files/zh-cn/web/javascript/guide/about/index.html135
-rw-r--r--files/zh-cn/web/javascript/guide/control_flow_and_error_handling/index.html441
-rw-r--r--files/zh-cn/web/javascript/guide/details_of_the_object_model/index.html758
-rw-r--r--files/zh-cn/web/javascript/guide/expressions_and_operators/index.html984
-rw-r--r--files/zh-cn/web/javascript/guide/functions/index.html662
-rw-r--r--files/zh-cn/web/javascript/guide/grammar_and_types/index.html705
-rw-r--r--files/zh-cn/web/javascript/guide/index.html135
-rw-r--r--files/zh-cn/web/javascript/guide/indexed_collections/index.html478
-rw-r--r--files/zh-cn/web/javascript/guide/introduction/index.html147
-rw-r--r--files/zh-cn/web/javascript/guide/iterators_and_generators/index.html200
-rw-r--r--files/zh-cn/web/javascript/guide/javascript_overview/index.html135
-rw-r--r--files/zh-cn/web/javascript/guide/keyed_collections/index.html155
-rw-r--r--files/zh-cn/web/javascript/guide/loops_and_iteration/index.html409
-rw-r--r--files/zh-cn/web/javascript/guide/meta_programming/index.html264
-rw-r--r--files/zh-cn/web/javascript/guide/modules/index.html460
-rw-r--r--files/zh-cn/web/javascript/guide/numbers_and_dates/index.html407
-rw-r--r--files/zh-cn/web/javascript/guide/regular_expressions/assertions/index.html263
-rw-r--r--files/zh-cn/web/javascript/guide/regular_expressions/boundaries/index.html6
-rw-r--r--files/zh-cn/web/javascript/guide/regular_expressions/character_classes/index.html216
-rw-r--r--files/zh-cn/web/javascript/guide/regular_expressions/groups_and_ranges/index.html164
-rw-r--r--files/zh-cn/web/javascript/guide/regular_expressions/index.html745
-rw-r--r--files/zh-cn/web/javascript/guide/regular_expressions/unicode_property_escapes/index.html171
-rw-r--r--files/zh-cn/web/javascript/guide/regular_expressions/量词/index.html170
-rw-r--r--files/zh-cn/web/javascript/guide/text_formatting/index.html252
-rw-r--r--files/zh-cn/web/javascript/guide/using_promises/index.html359
-rw-r--r--files/zh-cn/web/javascript/guide/working_with_objects/index.html522
26 files changed, 9343 insertions, 0 deletions
diff --git a/files/zh-cn/web/javascript/guide/about/index.html b/files/zh-cn/web/javascript/guide/about/index.html
new file mode 100644
index 0000000000..115939595c
--- /dev/null
+++ b/files/zh-cn/web/javascript/guide/about/index.html
@@ -0,0 +1,135 @@
+---
+title: 关于本指南
+slug: Web/JavaScript/Guide/About
+tags:
+ - JavaScript
+ - 初学者
+ - 指南
+translation_of: Web/JavaScript/Guide/Introduction
+---
+<p>JavaScript 是一种跨平台的,基于对象的脚本语言。本指南介绍了所有您使用 JavaScript 所需要了解的事情。</p>
+
+<h2 id="JavaScript_各版本中的新特性">JavaScript 各版本中的新特性</h2>
+
+
+<p></p><ul>
+<li><a href="/zh-CN/docs/Web/JavaScript/New_in_JavaScript/1.2">JavaScript 1.2的新特性</a></li><li><a href="/zh-CN/docs/Web/JavaScript/New_in_JavaScript/1.3">JavaScript 1.3的新特性</a></li><li><a href="/zh-CN/docs/Web/JavaScript/New_in_JavaScript/1.4">JavaScript 1.4的新特性</a></li><li><a href="/zh-CN/docs/Web/JavaScript/New_in_JavaScript/1.5">JavaScript 1.5 的新特性</a></li><li><a href="/zh-CN/docs/Web/JavaScript/New_in_JavaScript/1.6">JavaScript 1.6 的新特性</a></li><li><a href="/zh-CN/docs/Web/JavaScript/New_in_JavaScript/1.7">JavaScript 1.7 的新特性</a></li><li><a href="/zh-CN/docs/Web/JavaScript/New_in_JavaScript/1.8">New in JavaScript 1.8</a></li><li><a href="/zh-CN/docs/Web/JavaScript/New_in_JavaScript/1.8.1">JavaScript 1.8.1 的新特性</a></li><li><a href="/zh-CN/docs/Web/JavaScript/New_in_JavaScript/1.8.5">JavaScript 1.8.5 的新特性</a></li>
+</ul><p></p>
+
+<h2 id="您应该已经了解的事情">您应该已经了解的事情</h2>
+
+<p>本指南假设您具有以下背景:</p>
+
+<ul>
+ <li>对互联网和万维网(WWW)有基本的理解。</li>
+ <li>对于超文本标记语言(HTML)的较好认知。</li>
+ <li>一些编程经验。如果你刚开始接触编程,请学习<a href="https://developer.mozilla.org/zh-CN/docs/JavaScript">JavaScript</a>页面所链接的教程</li>
+</ul>
+
+<h2 id="JavaScript_版本">JavaScript 版本</h2>
+
+<table class="standard-table">
+ <caption>表格 1 JavaScript 和 Navigator 版本对照</caption>
+ <thead>
+ <tr>
+ <th scope="col">JavaScript 版本</th>
+ <th scope="col">Navigator 版本</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>JavaScript 1.0</td>
+ <td>Navigator 2.0</td>
+ </tr>
+ <tr>
+ <td>JavaScript 1.1</td>
+ <td>Navigator 3.0</td>
+ </tr>
+ <tr>
+ <td>JavaScript 1.2</td>
+ <td>Navigator 4.0-4.05</td>
+ </tr>
+ <tr>
+ <td>JavaScript 1.3</td>
+ <td>Navigator 4.06-4.7x</td>
+ </tr>
+ <tr>
+ <td>JavaScript 1.4</td>
+ <td> </td>
+ </tr>
+ <tr>
+ <td>JavaScript 1.5</td>
+ <td>Navigator 6.0<br>
+ Mozilla (开源浏览器)</td>
+ </tr>
+ <tr>
+ <td>JavaScript 1.6</td>
+ <td><a href="/en/Firefox_1.5_for_developers" title="en/Firefox_1.5_for_developers">Firefox 1.5</a>,及其它基于 Mozilla 1.8 的产品</td>
+ </tr>
+ <tr>
+ <td>JavaScript 1.7</td>
+ <td><a href="/en/Firefox_2_for_developers" title="en/Firefox_2_for_developers">Firefox 2</a>,及其它基于 Mozilla 1.8.1 的产品</td>
+ </tr>
+ <tr>
+ <td>JavaScript 1.8</td>
+ <td><a href="/en/Firefox_3_for_developers" title="en/Firefox_3_for_developers">Firefox 3</a>,及其它基于 Gecko 1.9 的产品</td>
+ </tr>
+ </tbody>
+</table>
+
+<h2 id="哪里可以找到_JavaScript_的信息">哪里可以找到 JavaScript 的信息</h2>
+
+<p>JavaScript 文档包括以下书目:</p>
+
+<ul>
+ <li><a href="/en/JavaScript/Guide" title="en/Core_JavaScript_1.5_Guide">JavaScript 指南</a> (即本指南)提供了关于 JavaScript 语言及其对象的有关信息。</li>
+ <li><a href="/en/JavaScript/Reference" title="en/JavaScript/Reference">JavaScript 参考</a> 提供 有关JavaScript 语言的参考资料。</li>
+</ul>
+
+<p>如果您刚刚开始接触 JavaScript,可以从<a href="/en/JavaScript/Guide" title="en/Core_JavaScript_1.5_Guide"> JavaScript 指南</a> 开始。一旦掌握了基础知识,您可以从 <a href="/en/JavaScript/Reference" title="en/JavaScript/Reference">JavaScript 参考</a> 中获得更多关于特定的对象和语句的细节。</p>
+
+<h2 id="学习_JavaScript_的窍门">学习 JavaScript 的窍门</h2>
+
+<p>开始学习 JavaScript 很容易:您只需要一个流行的 Web 浏览器即可。这本指南中包含了一些仅在 Firefox(以及其它基于 Gecko 的浏览器)的近期版本中才有的特性,因此,建议您使用最新的 Firefox 浏览器。</p>
+
+<p>在Firefox中内嵌了两个用于测验JavaScript非常有效的工具: Web终端和Scratchpad。</p>
+
+<h3 id="Web终端">Web终端</h3>
+
+<p><a href="/en-US/docs/Tools/Web_Console">web终端</a>会显示有关当前装载网页的信息,并且还包含<a href="https://developer.mozilla.org/en-US/docs/Tools/Web_Console#The_command_line_interpreter">命令行</a>,您可以用它在当前的网页中执行 JavaScript 语句。</p>
+
+<p>要打开 web 终端,请在 Firefox 中的“工具”菜单中选择 “Web Developer“ 中的 "Web Console"。它显示在浏览器窗口的底部。在终端的底部是一个命令行,你可以输入 JavaScript, 而在上面的面板中可以看到输出。</p>
+
+<p><img alt="Image:ErrorConsole.png" class="internal" src="https://mdn.mozillademos.org/files/7363/web-console-commandline.png" style="height: 589px; width: 878px;"></p>
+
+<h3 id="Scratchpad">Scratchpad</h3>
+
+<p>Web Console 在执行 JavaScript 的单个命令行时是非常好的,但是在执行多行命令时就没那么方便了,而且你也不可能在 Web Console 中保存你的代码。因此对于更复杂的例子,  <a href="https://developer.mozilla.org/en-US/docs/Tools/Scratchpad">Scratchpad</a> 是一个更好的工具。</p>
+
+<p> </p>
+
+<p>要打开 Scratchpad, 可以在 "Web Developer" 菜单下选择 "Scratchpad" , 它在 Firefox 中也位于 "Tools" 菜单下。它是一个单独的窗口以及编辑器,你可以使用它来写和执行浏览器中的代码。你也同样可以将脚本保存在硬盘,并且从硬盘装载。</p>
+
+<p>如果你选择了 "Inspect",  pad 中的代码会在浏览器中执行,其结果也会以 comment 的形式插入到 pad 中: </p>
+
+<p><img src="https://mdn.mozillademos.org/files/7365/scratchpad.png"></p>
+
+<h2 id="文档约定">文档约定</h2>
+
+<p>JavaScript 应用可以运行在许多操作系统之上;本书中所给出的信息适用于所有这些系统。文件和目录的路径将以 Windows 的形式给出(反斜线用于分隔目录名)。对于 Unix 系统,目录的路径是相同的,只是将反斜线换成斜线即可。</p>
+
+<p>本指南使用如下形式的统一资源定位符(URL):</p>
+
+<p><code>http://<em>server</em>.<em>domain</em>/<em>path</em>/<em>file</em>.html</code></p>
+
+<p>在这些 URL 中,<em>server</em> 表示您的应用所运行的服务器的名称,比如 <code>research1</code> 或者 <code>www</code>;<em>domain</em> 表示您的互联网域名,比如 <code>netscape.com</code> 或者 <code>uiuc.edu</code>; <em>path</em> 表示在服务器中的目录结构;而 <em>file</em><code>.html</code> 则表示特定的文件名。一般来讲,URL 中的斜体部分为占位符,而其中的等宽字体则为原文。如果您的服务器启用了安全套接字层(SSL),则需要将 URL 中的 <code>http</code> 换成 <code>https。</code></p>
+
+<p>本指南使用如下字体约定:</p>
+
+<ul>
+ <li>等宽字体用于示例代码,代码罗列,API 以及语言元素(比如方法名或者属性名),文件名,路径名,目录名,HTML 标签,以及其它任何必需键入到屏幕中的文本。(等宽斜体字用于代码中的占位符)</li>
+ <li><em>斜体字</em> 用于本书的标题,强调,变量和占位符以及其它直接字面上的词汇。</li>
+ <li><strong>粗体</strong> 用于词汇表。</li>
+</ul>
+
+<div>{{ PreviousNext("JavaScript/Guide", "JavaScript/Guide/JavaScript_Overview") }}</div>
diff --git a/files/zh-cn/web/javascript/guide/control_flow_and_error_handling/index.html b/files/zh-cn/web/javascript/guide/control_flow_and_error_handling/index.html
new file mode 100644
index 0000000000..b2fe41baef
--- /dev/null
+++ b/files/zh-cn/web/javascript/guide/control_flow_and_error_handling/index.html
@@ -0,0 +1,441 @@
+---
+title: 流程控制与错误处理
+slug: Web/JavaScript/Guide/Control_flow_and_error_handling
+tags:
+ - JavaScript
+translation_of: Web/JavaScript/Guide/Control_flow_and_error_handling
+---
+<p>{{jsSidebar("JavaScript Guide")}}{{PreviousNext("Web/JavaScript/Guide/Grammar_and_Types", "Web/JavaScript/Guide/Loops_and_iteration")}}</p>
+
+<p class="summary">JavaScript 提供一套灵活的语句集,<span class="notranslate">特别是控制流语句</span>,你可以<span class="notranslate">用它</span>在你的应用程序中实现大量的交互性功能。本章节我们将带来关于JavaScript语句的一些概览。</p>
+
+<p> 这一章中的语句,在 <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements">JavaScript参考</a> 中包含更为详尽的细节。在 JavaScript 代码中,分号(;)字符被用来分割语句。</p>
+
+<p>在JavaScript中,任何表达式(expression)都可以看作一条语句(statement),如果你想了解表达式的详细信息,可以阅读<a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators">表达式与运算符(Expressions and operators)</a>这一章节。</p>
+
+<h2 id="语句块">语句块</h2>
+
+<p>最基本的语句是用于组合语句的语句块。该块由一对大括号界定:</p>
+
+<pre class="syntaxbox">{
+ statement_1;
+  statement_2;
+   statement_3;
+ .
+  .
+  .
+ statement_n;
+}</pre>
+
+<h3 id="示例"><strong>示例</strong></h3>
+
+<p>语句块通常用于流程控制,如<code>if</code>,<code>for</code>,<code>while</code>等等。</p>
+
+<div style="margin-right: 270px;">
+<pre class="brush: js">while (x &lt; 10) {
+ x++;
+}</pre>
+</div>
+
+<p>这里<code>{ x++; }</code>就是语句块。</p>
+
+<div>
+<p><strong>重要</strong>:在ECMAScript 6标准之前,Javascript没有块作用域。在一个块中引入的变量的作用域是包含函数或脚本,并且设置它们的效果会延续到块之外。换句话说,块语句不定义范围。JavaScript中的“独立”块会产生与C或Java中完全不同的结果。示例:</p>
+</div>
+
+<pre class="brush: js">var x = 1;
+{
+ var x = 2;
+}
+alert(x); // 输出的结果为 2
+</pre>
+
+<p>这段代码的输出是<strong>2</strong>,这是因为块级作用域中的 var x变量声明与之前的声明在同一个作用域内。在C语言或是Java语言中,同样的代码输出的结果是1。</p>
+
+<p>从 ECMAScript 2015 开始,使用 <code>let</code> 和<code>const</code>变量是块作用域的。 更多信息请参考 {{jsxref("Statements/let", "let")}} 和 {{jsxref("Statements/const", "const")}}。</p>
+
+<h2 id="条件判断语句">条件判断语句</h2>
+
+<p>条件判断语句指的是根据指定的条件所返回的结果(真或假或其它预定义的),来执行特定的语句。JavaScript 支持两种条件判断语句:<code>if...else</code>和<code>switch</code>。</p>
+
+<h3 id="if...else_语句"><code>if...else</code> 语句</h3>
+
+<p>当一个逻辑条件为真,用if语句执行一个语句。当这个条件为假,使用可选择的 else 从句来执行这个语句。if 语句如下所示:</p>
+
+<pre class="brush: js">if (condition) {
+ statement_1;
+}else {
+ statement_2;
+} //推荐使用严格的语句块模式,语句else可选
+</pre>
+
+<p>条件可以是任何返回结果被计算为true 或 false的表达式。如果条件表达式返回的是 true,statement_1 语句会被执行;否则,statement_2 被执行。statement_1 和 statement_2 可以是任何语句,甚至你可以将另一个if语句嵌套其中。 </p>
+
+<p>你也可以组合语句通过使用 <code>else if</code> 来测试连续多种条件判断,就像下面一样:</p>
+
+<pre class="brush: js">if (condition_1) {
+ statement_1;
+}else if (condition_2) {
+ statement_2;
+}else if (condition_n_1) {
+ statement_n;
+}else {
+ statement_last;
+}
+</pre>
+
+<p>要执行多个语句,可以使用语句块({ ... }) 来分组这些语句。通常,总是使用语句块是一个好的习惯,特别是在代码涉及比较多的 if 语句时:</p>
+
+<pre class="brush: js">if (条件) {
+  当条件为真的时候,执行语句1;
+  当条件为真的时候,执行语句2;
+} else {
+ 当条件为假的时候,执行语句3;
+  当条件为假的时候,执行语句4;
+}
+</pre>
+
+<p>不建议在条件表达式中使用赋值语句,因为在快速查阅代码时容易把它看成等值比较。例如,不要使用下面的代码:</p>
+
+<div class="blockIndicator warning">
+<p>   if(x = y){</p>
+
+<p> /*  语句  */</p>
+
+<p>}</p>
+</div>
+
+<p>如果你需要在条件表达式中使用赋值,通常在赋值语句前后额外添加一对括号。例如: </p>
+
+
+
+<pre><code>if ((x = y)) {
+ /* statements here */
+}</code></pre>
+
+
+
+<h4 id="错误的值">错误的值</h4>
+
+<p>下面这些值将被计算出 false (also known as {{Glossary("Falsy")}} values):</p>
+
+<ul>
+ <li><code>false</code></li>
+ <li><code>undefined</code></li>
+ <li><code>null</code></li>
+ <li><code>0</code></li>
+ <li><code>NaN</code></li>
+ <li>空字符串(<code>""</code>)</li>
+</ul>
+
+<p>当传递给条件语句所有其他的值,包括所有对象会被计算为真 。</p>
+
+<p>请不要混淆原始的布尔值<code>true</code>和<code>false</code> 与 {{jsxref("Boolean")}}对象的真和假。例如:</p>
+
+<pre class="brush: js"><code class="language-js"><span class="keyword token">var</span> b <span class="operator token">=</span> <span class="keyword token">new</span> <span class="class-name token">Boolean</span><span class="punctuation token">(</span><span class="keyword token">false</span><span class="punctuation token">)</span><span class="punctuation token">;</span>
+<span class="keyword token">if</span> <span class="punctuation token">(</span>b<span class="punctuation token">)</span> <span class="comment token">//结果视为真</span>
+<span class="keyword token">if</span> <span class="punctuation token">(</span>b <span class="operator token">==</span> <span class="keyword token">true</span><span class="punctuation token">)</span> <span class="comment token">// 结果视为假</span></code></pre>
+
+<h4 id="示例_2"><strong>示例</strong></h4>
+
+<p>在以下示例中,如果<code>Text</code>对象中的字符数为3,函数<code>checkData</code>将返回<code>true</code>;否则,显示警报并返回<code>false</code>。</p>
+
+<pre class="brush: js">function checkData() {
+ if (document.form1.threeChar.value.length == 3) {
+ return true;
+ } else {
+ alert("Enter exactly three characters. " +
+ document.form1.threeChar.value + " is not valid.");
+ return false;
+ }
+}
+</pre>
+
+<h3 id="switch_语句"><code>switch</code> 语句</h3>
+
+<p><code>switch</code> 语句允许一个程序求一个表达式的值并且尝试去匹配表达式的值到一个 <code>case</code> 标签。如果匹配成功,这个程序执行相关的语句。<code>switch</code> 语句如下所示:</p>
+
+<pre class="brush: js">switch (expression) {
+ case label_1:
+ statements_1
+ [break;]
+ case label_2:
+ statements_2
+ [break;]
+ ...
+ default:
+ statements_def
+ [break;]
+}
+</pre>
+
+<p>程序首先查找一个与 <code>expression </code>匹配的 <code>case </code>语句,然后将控制权转移到该子句,执行相关的语句。如果没有匹配值, 程序会去找 <code>default </code>语句,如果找到了,控制权转移到该子句,执行相关的语句。如果没有找到 <code>default</code>,程序会继续执行 <code>switch </code>语句后面的语句。<code>default</code> 语句通常出现在switch语句里的最后面,当然这不是必须的。</p>
+
+<p><code>可选的 break</code> 语句与每个 <code>case</code> 语句相关联, 保证在匹配的语句被执行后程序可以跳出 <code>switch </code>并且继续执行 <code>switch</code> 后面的语句。如果break被忽略,则程序将继续执行switch语句中的下一条语句。</p>
+
+<p><strong>示例</strong><br>
+ 在如下示例中, 如果 <code>fruittype</code> 等于 "Bananas", 程序匹配到对应 "Bananas" 的<code>case</code> 语句,并执行相关语句。 当执行到 <code>break</code> 时,程序结束了 <code>switch</code> 并执行 <code>switch</code> 后面的语句。 如果不写 <code>break</code> ,那么程序将会执行 <code>case "Cherries"</code> 下的语句。</p>
+
+<pre class="brush: js">switch (fruittype) {
+ case "Oranges":
+ document.write("Oranges are $0.59 a pound.&lt;br&gt;");
+ break;
+ case "Apples":
+ document.write("Apples are $0.32 a pound.&lt;br&gt;");
+ break;
+ case "Bananas":
+ document.write("Bananas are $0.48 a pound.&lt;br&gt;");
+ break;
+ case "Cherries":
+ document.write("Cherries are $3.00 a pound.&lt;br&gt;");
+ break;
+ case "Mangoes":
+ case "Papayas":
+ document.write("Mangoes and papayas are $2.79 a pound.&lt;br&gt;");
+ break;
+ default:
+ document.write("Sorry, we are out of " + fruittype + ".&lt;br&gt;");
+}
+document.write("Is there anything else you'd like?&lt;br&gt;");
+</pre>
+
+<h2 id="异常处理语句">异常处理语句</h2>
+
+<p>你可以用 <code>throw</code> 语句抛出一个异常并且用 <code>try...catch</code> 语句捕获处理它。</p>
+
+<ul>
+ <li><a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Guide/Control_flow_and_error_handling$edit#throw_statement"><code>throw</code> </a>语句</li>
+ <li><a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Guide/Control_flow_and_error_handling$edit#try...catch_statement"><code>try...catch</code> </a>语句</li>
+</ul>
+
+<h3 id="异常类型">异常类型</h3>
+
+<p>JavaScript 可以抛出任意对象。然而,不是所有对象能产生相同的结果。尽管抛出数值或者字母串作为错误信息十分常见,但是通常用下列其中一种异常类型来创建目标更为高效:</p>
+
+<ul>
+ <li><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error#Error_types">ECMAScript exceptions</a></li>
+ <li>{{domxref("DOMException")}} and {{domxref("DOMError")}}</li>
+</ul>
+
+<h3 id="throw_语句"><code>throw</code> 语句</h3>
+
+<p>使用<font face="Courier New, Andale Mono, monospace"><code>throw</code>语句抛出一个异常。当你抛出异常,你规定一个含有值的表达式要被抛出。</font></p>
+
+<pre class="brush: js">throw expression;
+</pre>
+
+<p>你可以抛出任意表达式而不是特定一种类型的表达式。下面的代码抛出了几个不同类型的表达式:</p>
+
+<pre class="brush: js">throw "Error2";   // String type
+throw 42;         // Number type
+throw true;       // Boolean type
+throw {toString: function() { return "I'm an object!"; } };
+
+</pre>
+
+<div class="note"><strong>注意:</strong>你可以在抛出异常时声明一个对象。那你就可以在catch块中查询到对象的属性。
+
+
+</div>
+
+<pre class="brush: js">// Create an object type UserException
+function UserException (message){
+ this.message=message;
+ this.name="UserException";
+}
+
+// Make the exception convert to a pretty string when used as
+// a string (e.g. by the error console)
+UserException.prototype.toString = function (){
+ return this.name + ': "' + this.message + '"';
+}
+
+// Create an instance of the object type and throw it
+throw new UserException("Value too high");</pre>
+
+<h3 id="try...catch_语句"><code>try...catch</code> 语句</h3>
+
+<p><code>try...catch</code> 语句标记一块待尝试的语句,并规定一个以上的响应应该有一个异常被抛出。如果我们抛出一个异常,<code>try...catch</code>语句就捕获它。</p>
+
+<p><code>try...catch</code> 语句有一个包含一条或者多条语句的try代码块,0个或1个的<code>catch</code>代码块,catch代码块中的语句会在try代码块中抛出异常时执行。 换句话说,如果你在try代码块中的代码如果没有执行成功,那么你希望将执行流程转入catch代码块。如果try代码块中的语句(或者<code>try</code> 代码块中调用的方法)一旦抛出了异常,那么执行流程会立即进入<code>catch</code> 代码块。如果try代码块没有抛出异常,catch代码块就会被跳过。<code>finally</code> 代码块总会紧跟在try和catch代码块之后执行,但会在try和catch代码块之后的其他代码之前执行。</p>
+
+<p>下面的例子使用了<code>try...catch</code>语句。示例调用了一个函数用于从一个数组中根据传递值来获取一个月份名称。如果该值与月份数值不相符,会抛出一个带有<code>"InvalidMonthNo"</code>值的异常,然后在捕捉块语句中设<code>monthName</code>变量为<code>unknown</code>。</p>
+
+<pre class="brush: js">function getMonthName(mo) {
+ mo = mo - 1; // Adjust month number for array index (1 = Jan, 12 = Dec)
+ var months = ["Jan","Feb","Mar","Apr","May","Jun","Jul",
+ "Aug","Sep","Oct","Nov","Dec"];
+ if (months[mo]) {
+ return months[mo];
+ } else {
+ throw "InvalidMonthNo"; //throw keyword is used here
+ }
+}
+
+try { // statements to try
+ monthName = getMonthName(myMonth); // function could throw exception
+}
+catch (e) {
+ monthName = "unknown";
+ logMyErrors(e); // pass exception object to error handler -&gt; your own function
+}</pre>
+
+<h4 id="The_catch_Block" name="The_catch_Block"><code>catch</code> 块</h4>
+
+<p>你可以使用<code>catch</code>块来处理所有可能在<code>try</code>块中产生的异常。</p>
+
+<pre class="brush: js">catch (catchID) {
+ statements
+}
+</pre>
+
+<p>捕捉块指定了一个标识符(上述语句中的<code>catchID</code>)来存放抛出语句指定的值;你可以用这个标识符来获取抛出的异常信息。在插入<code>throw</code>块时JavaScript创建这个标识符;标识符只存在于<code>catch</code>块的存续期间里;当<code>catch</code>块执行完成时,标识符不再可用。</p>
+
+<p>举个例子,下面代码抛出了一个异常。当异常出现时跳到<code>catch</code>块。</p>
+
+<pre class="brush: js">try {
+ throw "myException" // generates an exception
+}
+catch (e) {
+// statements to handle any exceptions
+ logMyErrors(e) // pass exception object to error handler
+}
+</pre>
+
+<h4 id="finally块"><code>finally</code>块</h4>
+
+<p><code>finally</code>块包含了在try和catch块完成后、下面接着try...catch的语句之前执行的语句。<code>finally</code>块无论是否抛出异常都会执行。如果抛出了一个异常,就算没有异常处理,<code>finally</code>块里的语句也会执行。</p>
+
+<p>你可以用<code>finally</code>块来令你的脚本在异常发生时优雅地退出;举个例子,你可能需要在绑定的脚本中释放资源。接下来的例子用文件处理语句打开了一个文件(服务端的JavaScript允许你进入文件)。如果在文件打开时一个异常抛出,<code>finally</code>块会在脚本错误之前关闭文件。</p>
+
+<pre class="brush: js">openMyFile();
+try {
+ writeMyFile(theData); //This may throw a error
+}catch(e){
+ handleError(e); // If we got a error we handle it
+}finally {
+ closeMyFile(); // always close the resource
+}
+</pre>
+
+<p>如果<code>finally</code>块返回一个值,该值会是整个<code>try-catch-finally</code>流程的返回值,不管在<code>try</code>和<code>catch</code>块中语句返回了什么:</p>
+
+<pre class="brush: js">function f() {
+  try {
+    console.log(0);
+    throw "bogus";
+  } catch(e) {
+    console.log(1);
+    return true; // this return statement is suspended
+                 // until finally block has completed
+    console.log(2); // not reachable
+  } finally {
+    console.log(3);
+    return false; // overwrites the previous "return"
+    console.log(4); // not reachable
+  }
+  // "return false" is executed now
+  console.log(5); // not reachable
+}
+f(); // console 0, 1, 3; returns false
+
+</pre>
+
+<p>用<code>finally</code>块覆盖返回值也适用于在<code>catch</code>块内抛出或重新抛出的异常:</p>
+
+<pre class="brush: js">function f() {
+ try {
+ throw 'bogus';
+ } catch(e) {
+ console.log('caught inner "bogus"');
+ throw e; // this throw statement is suspended until
+ // finally block has completed
+ } finally {
+ return false; // overwrites the previous "throw"
+ }
+ // "return false" is executed now
+}
+
+try {
+ f();
+} catch(e) {
+ // this is never reached because the throw inside
+ // the catch is overwritten
+ // by the return in finally
+ console.log('caught outer "bogus"');
+}
+
+// OUTPUT
+// caught inner "bogus"
+</pre>
+
+<h4 id="Nesting_try...catch_Statements" name="Nesting_try...catch_Statements">嵌套 try...catch 语句</h4>
+
+<p>你可以嵌套一个或多个<code>try ... catch</code>语句。如果一个内部<code>try ... catch</code>语句没有<code>catch</code>块,它需要有一个<code>finally</code>块,并且封闭的<code>try ... catch</code>语句的<code>catch</code>块被检查匹配。有关更多信息,请参阅<a href="/zh-CN/docs/Web/JavaScript/Reference/Statements/try...catch">try... catch</a>参考页上的<a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/try...catch#Nested_try-blocks">嵌套try-blocks</a>。</p>
+
+<h3 id="使用Error对象">使用<code>Error</code>对象</h3>
+
+<p>根据错误类型,你也许可以用'name'和'message'获取更精炼的信息。'name'提供了常规的错误类(如 'DOMException' 或 'Error'),而'message'通常提供了一条从错误对象转换成字符串的简明信息。</p>
+
+<p>在抛出你个人所为的异常时,为了充分利用那些属性(比如你的<code>catch</code>块不能分辨是你个人所为的异常还是系统的异常时),你可以使用 Error 构造函数。比如:</p>
+
+<pre class="brush: js">function doSomethingErrorProne () {
+  if (ourCodeMakesAMistake()) {
+    throw (new Error('The message'));
+  } else {
+    doSomethingToGetAJavascriptError();
+  }
+}
+....
+try {
+  doSomethingErrorProne();
+}
+catch (e) {
+  console.log(e.name); // logs 'Error'
+  console.log(e.message); // logs 'The message' or a JavaScript error message)
+}</pre>
+
+<h2 id="Promises">Promises</h2>
+
+<p>从 ECMAScript 6 开始,JavaScript 增加了对 {{jsxref("Promise")}} 对象的支持,它允许你对延时和异步操作流进行控制。</p>
+
+<p><code>Promise</code> 对象有以下几种状态:</p>
+
+<ul>
+ <li><em>pending:</em>初始的状态,即正在执行,不处于 fulfilled 或 rejected 状态。</li>
+ <li><em>fulfilled:</em>成功的完成了操作。</li>
+ <li><em>rejected:</em>失败,没有完成操作。</li>
+ <li><em>settled:</em>Promise 处于 fulfilled 或 rejected 二者中的任意一个状态, 不会是 pending。</li>
+</ul>
+
+<p><img alt="" src="https://mdn.mozillademos.org/files/8633/promises.png" style="height: 297px; width: 801px;"></p>
+
+<h3 id="通过_XHR_加载图片">通过 XHR 加载图片</h3>
+
+<p>你可以在 MDN GitHub <a href="https://github.com/mdn/js-examples/tree/master/promises-test">promise-test</a> 中找到这个简单的例子,它使用了 Promise 和 <code><a href="https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest">XMLHttpRequest</a></code> 来加载一张图片,你也可以直接在<a href="https://mdn.github.io/js-examples/promises-test/">这个页面</a>查看他的效果。同时为了让你更清楚的了解 Promise 和 XHR 的结构,代码中每一个步骤后都附带了注释。</p>
+
+<p>这里有一个未注释的版本,展现了 <code>Promise</code> 的工作流,希望可以对你的理解有所帮助。</p>
+
+<pre class="brush: js">function imgLoad(url) {
+ return new Promise(function(resolve, reject) {
+ var request = new XMLHttpRequest();
+ request.open('GET', url);
+ request.responseType = 'blob';
+ request.onload = function() {
+ if (request.status === 200) {
+ resolve(request.response);
+ } else {
+ reject(Error('Image didn\'t load successfully; error code:'
+ + request.statusText));
+ }
+ };
+ request.onerror = function() {
+ reject(Error('There was a network error.'));
+ };
+ request.send();
+ });
+}</pre>
+
+<p>若想了解更详细的信息,请参阅 {{jsxref("Promise")}} 页面。</p>
+
+<div>{{PreviousNext("Web/JavaScript/Guide/Grammar_and_types", "Web/JavaScript/Guide/Loops_and_iteration")}}</div>
diff --git a/files/zh-cn/web/javascript/guide/details_of_the_object_model/index.html b/files/zh-cn/web/javascript/guide/details_of_the_object_model/index.html
new file mode 100644
index 0000000000..f140ba8e84
--- /dev/null
+++ b/files/zh-cn/web/javascript/guide/details_of_the_object_model/index.html
@@ -0,0 +1,758 @@
+---
+title: 对象模型的细节
+slug: Web/JavaScript/Guide/Details_of_the_Object_Model
+tags:
+ - JavaScript
+ - Object
+ - 中级
+ - 教程
+translation_of: Web/JavaScript/Guide/Details_of_the_Object_Model
+---
+<div>{{jsSidebar("JavaScript Guide")}} {{PreviousNext("Web/JavaScript/Guide/Working_with_Objects", "Web/JavaScript/Guide/Using_promises")}}</div>
+
+<p class="summary">JavaScript 是一种基于原型而不是基于类的基于对象(object-based)语言。正是由于这一根本的区别,其如何创建对象的层级结构以及对象的属性与属性值是如何继承的并不是那么清晰。本节试着阐明。</p>
+
+<p>本节假设您已经有一些 JavaScript 基础,并且用 JavaScript 函数创建过简单的对象。</p>
+
+<h2 id="class-based_vs_prototype-based_languages" name="class-based_vs_prototype-based_languages">基于类 vs 基于原型的语言</h2>
+
+<p>基于类的面向对象语言,比如 Java 和 C++,是构建在两个不同实体之上的:类和实例。</p>
+
+<ul>
+ <li>一个<em>类(class)</em>定义了某一对象集合所具有的特征性属性(可以将 Java 中的方法和域以及 C++ 中的成员都视作属性)。类是抽象的,而不是其所描述的对象集合中的任何特定的个体。例如 <code>Employee</code> 类可以用来表示所有雇员的集合。</li>
+ <li>另一方面,一个<em>实例(instance)</em>是一个<em>类</em>的实例化。例如, <code>Victoria</code> 可以是 <code>Employee</code> 类的一个实例,表示一个特定的雇员个体。实例具有和其父类完全一致的属性,不多也不少。</li>
+</ul>
+
+<p>基于原型的语言(如 JavaScript)并不存在这种区别:它只有对象。基于原型的语言具有所谓<em>原型对象(prototypical object)</em>的概念。原型对象可以作为一个模板,新对象可以从中获得原始的属性。任何对象都可以指定其自身的属性,既可以是创建时也可以在运行时创建。而且,任何对象都可以作为另一个对象的<em>原型(prototype)</em>,从而允许后者共享前者的属性。</p>
+
+<h3 id="定义类">定义类</h3>
+
+<p>在基于类的语言中,需要专门的<em>类定义(class definition)</em>来定义类。在定义类时,允许定义被称为<em>构造器(constructor)</em>的特殊的方法来创建该类的实例。在构造器方法中,可以指定实例的属性的初始值并做一些其他的操作。你可以通过使用 <code>new</code> 操作符来创建类的实例。</p>
+
+<p>JavaScript 大体上与之类似,但并没有专门的<em>类定义</em>,你通过定义构造函数的方式来创建一系列有着特定初始值和方法的对象。任何JavaScript函数都可以被用作构造函数。你也可以使用 <code>new</code> 操作符来创建一个新对象。</p>
+
+<div class="blockIndicator note">
+<p><strong>提示:</strong>在ES6中引入了 <a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Classes">类定义</a> ,但它实际上是已有的原型继承方式的语法糖而已,并没有引入新的面向对象继承模型。</p>
+</div>
+
+<h3 id="子类和继承">子类和继承</h3>
+
+<p>基于类的语言是通过对类的定义中构建类的层级结构的。在类定义中,可以指定新的类是一个现存的类的子类。子类将继承父类的全部属性,并可以添加新的属性或者修改继承的属性。例如,假设 <code>Employee</code> 类只有 <code>name</code> 和 <code>dept</code> 属性,而 <code>Manager</code> 是 <code>Employee</code> 的子类并添加了 <code>reports</code> 属性。这时,<code>Manager</code> 类的实例将具有所有三个属性:<code>name</code>,<code>dept</code>和<code>reports</code>。</p>
+
+<p>JavaScript 通过将构造器函数与原型对象相关联的方式来实现继承。这样,您可以创建完全一样的 <code>Employee</code> — <code>Manager</code> 示例,不过需要使用略微不同的术语。首先,定义Employee构造函数,在该构造函数内定义name、dept属性;接下来,定义Manager构造函数,在该构造函数内调用Employee构造函数,并定义reports属性;最后,将一个获得了Employee.prototype(Employee构造函数原型)的新对象赋予manager构造函数,以作为Manager构造函数的原型。之后当你创建新的Manager对象实例时,该实例会从Employee对象继承name、dept属性。</p>
+
+<h3 id="添加和移除属性">添加和移除属性</h3>
+
+<p>在基于类的语言中,通常在编译时创建类,然后在编译时或者运行时对类的实例进行实例化。一旦定义了类,无法对类的属性进行更改。然而,在 JavaScript 中,允许运行时添加或者移除任何对象的属性。如果您为一个对象中添加了一个属性,而这个对象又作为其它对象的原型,则以该对象作为原型的所有其它对象也将获得该属性。</p>
+
+<h3 id="差异总结">差异总结</h3>
+
+<p>下面的表格摘要给出了上述区别。本节的后续部分将描述有关使用 JavaScript 构造器和原型创建对象层级结构的详细信息,并将其与在 Java 中的做法加以对比。</p>
+
+<table class="fullwidth-table">
+ <caption>基于类(Java)和基于原型(JavaScript)的对象系统的比较</caption>
+ <thead>
+ <tr>
+ <th scope="col">基于类的(Java)</th>
+ <th scope="col">基于原型的(JavaScript)</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>类和实例是不同的事物。</td>
+ <td>所有对象均为实例。</td>
+ </tr>
+ <tr>
+ <td>通过类定义来定义类;通过构造器方法来实例化类。</td>
+ <td>通过构造器函数来定义和创建一组对象。</td>
+ </tr>
+ <tr>
+ <td>通过 <code>new</code> 操作符创建单个对象。</td>
+ <td>相同。</td>
+ </tr>
+ <tr>
+ <td>通过类定义来定义现存类的子类,从而构建对象的层级结构。</td>
+ <td>指定一个对象作为原型并且与构造函数一起构建对象的层级结构</td>
+ </tr>
+ <tr>
+ <td>遵循类链继承属性。</td>
+ <td>遵循原型链继承属性。</td>
+ </tr>
+ <tr>
+ <td>类定义指定类的所有实例的<strong>所有</strong>属性。无法在运行时动态添加属性。</td>
+ <td>构造器函数或原型指定实例的<strong>初始</strong>属性集。允许动态地向单个的对象或者整个对象集中添加或移除属性。</td>
+ </tr>
+ </tbody>
+</table>
+
+<h2 id="Employee_示例">Employee 示例</h2>
+
+<p>本节的余下部分将使用如下图所示的 Employee 层级结构。</p>
+
+<p><img alt="" src="https://mdn.mozillademos.org/files/3060/figure8.1.png"></p>
+
+<div style="display: table-cell; vertical-align: middle; padding: 10px;">
+<ul>
+ <li><code>Employee</code> 具有 <code>name</code> 属性(默认值为空的字符串)和 <code>dept</code> 属性(默认值为 "general")。</li>
+ <li><code>Manager</code> 是 <code>Employee</code>的子类。它添加了 <code>reports</code> 属性(默认值为空的数组,以 <code>Employee</code> 对象数组作为它的值)。</li>
+ <li><code>WorkerBee</code> 是 <code>Employee</code>的子类。它添加了 <code>projects</code> 属性(默认值为空的数组,以字符串数组作为它的值)。</li>
+ <li><code>SalesPerson</code> 是 <code>WorkerBee</code>的子类。它添加了 <code>quota</code> 属性(其值默认为 100)。它还重载了 <code>dept</code> 属性值为 "sales",表明所有的销售人员都属于同一部门。</li>
+ <li><code>Engineer</code> 基于 <code>WorkerBee</code>。它添加了 <code>machine</code> 属性(其值默认为空字符串)同时重载了 <code>dept</code> 属性值为 "engineering"。</li>
+</ul>
+</div>
+
+<h2 id="创建层级结构">创建层级结构</h2>
+
+<p>可以有几种不同的方式来定义适当的构造器函数,从而实现雇员的层级结构。如何选择很大程度上取决于您希望在您的应用程序中能做到什么。</p>
+
+<p>本节介绍了如何使用非常简单的(同时也是相当不灵活的)定义,使得继承得以实现。在定义完成后,就无法在创建对象时指定属性的值。新创建的对象仅仅获得了默认值,当然允许随后加以修改。图例 8.2 展现了这些简单的定义形成的层级结构。</p>
+
+<p>在实际应用程序中,您很可能想定义构造器,以允许您在创建对象时指定属性值。(参见<a href="#More_flexible_constructors">More flexible constructors</a>)。当前,这些简单的定义只是说明了继承是如何实现的。</p>
+
+<p>下面关于 <code>Employee</code> 的 Java 和 JavaScript 的定义是非常类似的。唯一的不同是在 Java 中需要指定每个属性的类型,而在 JavaScript 中则不需要(这是因为Java是 <a href="https://zh.wikipedia.org/wiki/%E5%BC%B7%E5%BC%B1%E5%9E%8B%E5%88%A5">强类型</a> 语言,而 JavaScript 是弱类型语言)。</p>
+
+<table class="standard-table">
+ <thead>
+ <tr>
+ <th scope="col">JavaScript</th>
+ <th scope="col">Java</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>
+ <pre class="brush: js notranslate">
+function Employee () {
+ this.name = "";
+ this.dept = "general";
+}
+</pre>
+ </td>
+ <td>
+ <pre class="brush: java notranslate">
+public class Employee {
+ public String name = "";
+ public String dept = "general";
+}</pre>
+ </td>
+ </tr>
+ </tbody>
+</table>
+
+<p><code>Manager 和 WorkerBee 的定义表示在如何指定继承链中上一层对象时,两者存在不同点。在 JavaScript 中,您会添加一个原型实例作为构造器函数prototype 属性的值,然后将该构造函数原型的构造器重载为其自身。这一动作可以在构造器函数定义后的任意时刻执行。而在 Java 中,则需要在类定义中指定父类,且不能在类定义之外改变父类。</code></p>
+
+<table class="standard-table">
+ <thead>
+ <tr>
+ <th scope="col">JavaScript</th>
+ <th scope="col">Java</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>
+ <pre class="brush: js notranslate">
+function Manager() {
+ Employee.call(this);
+ this.reports = [];
+}
+Manager.prototype = Object.create(Employee.prototype);
+
+function WorkerBee() {
+ Employee.call(this);
+ this.projects = [];
+}
+WorkerBee.prototype = Object.create(Employee.prototype);</pre>
+ </td>
+ <td>
+ <pre class="brush: java notranslate">
+public class Manager extends Employee {
+ public Employee[] reports = new Employee[0];
+}
+
+
+
+public class WorkerBee extends Employee {
+ public String[] projects = new String[0];
+}</pre>
+ </td>
+ </tr>
+ </tbody>
+</table>
+
+<p>在对<code>Engineer</code> 和 <code>SalesPerson</code> 定义时,创建了继承自 <code>WorkerBee</code> 的对象,该对象会进而继承自<code>Employee</code>。这些对象会具有在这个链之上的所有对象的属性。另外,它们在定义时,又重载了继承的 <code>dept</code> 属性值,赋予新的属性值。</p>
+
+<table class="standard-table">
+ <thead>
+ <tr>
+ <th scope="col">JavaScript</th>
+ <th scope="col">Java</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>
+ <pre class="brush: js notranslate">
+function SalesPerson() {
+ WorkerBee.call(this);
+ this.dept = 'sales';
+ this.quota = 100;
+}
+SalesPerson.prototype = Object.create(WorkerBee.prototype);
+
+function Engineer() {
+ WorkerBee.call(this);
+ this.dept = 'engineering';
+ this.machine = '';
+}
+Engineer.prototype <code>= Object.create(WorkerBee.prototype);</code></pre>
+ </td>
+ <td>
+ <pre class="brush: java notranslate">
+<code>public class SalesPerson extends WorkerBee {
+ public String dept = "sales";
+ public double quota = 100.0;
+}
+
+
+public class Engineer extends WorkerBee {
+ public String dept = "engineering";
+ public String machine = "";
+}</code></pre>
+ </td>
+ </tr>
+ </tbody>
+</table>
+
+<p>使用这些定义,您可以创建这些对象的实例,以获取其属性的默认值。下图说明了如何使用这些 JavaScript 定义创建新对象并显示新对象的属性值。</p>
+
+<div class="note">
+<p><strong>提示:</strong>实例在基于类的语言中具有特定的技术含义。在这些语言中,一个实例是一个类的单独实例化,与一个类本质上是不同的。在 JavaScript 中,“实例”没有这个技术含义,因为JavaScript在类和实例之间不存在这样的区别。然而,在讨论 JavaScript 时,可以非正式地使用“实例”来表示使用特定构造函数创建的对象。 所以,在这个例子中,你可以非正式地说<code>jane</code> 是 <code>Engineer</code>的一个实例。同样,虽然术语 parent,child,ancestor 和 descendant 在 JavaScript 中没有正式含义;你可以非正式地使用它们来引用原型链中较高或更低的对象。</p>
+</div>
+
+<h3 id="用简单的定义创建对象">用简单的定义创建对象</h3>
+
+<h4 id="对象层次结构">对象层次结构</h4>
+
+<p>使用右侧的代码创建以下层次结构。</p>
+
+<p><img src="https://mdn.mozillademos.org/files/10412/=figure8.3.png"></p>
+
+<h4 id="个别对象">个别对象</h4>
+
+<pre class="brush: js notranslate">var jim = new Employee; // 如构造函数无须接受任何参数,圆括号可以省略。
+// jim.name is ''
+// jim.dept is 'general'
+
+var sally = new Manager;
+// sally.name is ''
+// sally.dept is 'general'
+// sally.reports is []
+
+var mark = new WorkerBee;
+// mark.name is ''
+// mark.dept is 'general'
+// mark.projects is []
+
+var fred = new SalesPerson;
+// fred.name is ''
+// fred.dept is 'sales'
+// fred.projects is []
+// fred.quota is 100
+
+var jane = new Engineer;
+// jane.name is ''
+// jane.dept is 'engineering'
+// jane.projects is []
+// jane.machine is ''</pre>
+
+<h2 id="对象的属性">对象的属性</h2>
+
+<p>本节将讨论对象如何从原型链中的其它对象中继承属性,以及在运行时添加属性的相关细节。</p>
+
+<h3 id="继承属性">继承属性</h3>
+
+<p>假设您通过如下语句创建一个<code>mark</code>对象作为 <code>WorkerBee</code>的实例:</p>
+
+<pre class="brush: js notranslate">var mark = new WorkerBee;
+</pre>
+
+<p>当 JavaScript 执行 <code>new</code> 操作符时,它会先创建一个普通对象,并将这个普通对象中的 [[prototype]] 指向 <code>WorkerBee.prototype</code> ,然后再把这个普通对象设置为执行 <code>WorkerBee</code> 构造函数时 <code>this</code>  的值。该普通对象的 [[Prototype]] 决定其用于检索属性的原型链。当构造函数执行完成后,所有的属性都被设置完毕,JavaScript 返回之前创建的对象,通过赋值语句将它的引用赋值给变量 <code>mark</code>。</p>
+
+<p>这个过程不会显式的将 <code style="font-size: 14px;">mark</code>所继承的原型链中的属性作为本地属性存放在 <code>mark</code> 对象中。当访问属性时,JavaScript 将首先检查对象自身中是否存在该属性,如果有,则返回该属性的值。如果不存在,JavaScript会检查原型链(使用内置的 [[Prototype]] )。如果原型链中的某个对象包含该属性,则返回这个属性的值。如果遍历整条原型链都没有找到该属性,JavaScript 则认为对象中不存在该属性,返回一个 <code>undefined</code>。这样,<code>mark</code> 对象中将具有如下的属性和对应的值:</p>
+
+<pre class="brush: js notranslate">mark.name = "";
+mark.dept = "general";
+mark.projects = [];
+</pre>
+
+<p><code>mark</code> 对象从 <code>mark.__proto__</code> 中保存的原型对象里继承了 <code>name</code> 和 <code>dept</code> 属性。并由 <code>WorkerBee</code> 构造函数为 <code>projects</code> 属性设置了本地值。 这就是 JavaScript 中的属性和属性值的继承。这个过程的一些微妙之处将在 <a href="#Property_inheritance_revisited">Property inheritance revisited</a> 中进一步讨论。</p>
+
+<p>由于这些构造器不支持为实例设置特定的值,所以这些属性值仅仅是创建自 <code>WorkerBee</code> 的所有对象所共享的默认值。当然这些属性的值是可以修改的,所以您可以为 <code>mark</code>指定特定的信息,如下所示:</p>
+
+<pre class="brush: js notranslate">mark.name = "Doe, Mark";
+mark.dept = "admin";
+mark.projects = ["navigator"];</pre>
+
+<h3 id="添加属性">添加属性</h3>
+
+<p>在 JavaScript 中,您可以在运行时为任何对象添加属性,而不必受限于构造函数提供的属性。添加特定于某个对象的属性,只需要为该对象指定一个属性值,如下所示:</p>
+
+<pre class="brush: js notranslate">mark.bonus = 3000;
+</pre>
+
+<p>这样 <code>mark</code> 对象就有了 <code>bonus</code> 属性,而其它 <code>WorkerBee</code> 则没有该属性。</p>
+
+<p>如果您向某个构造函数的原型对象中添加新的属性,那么该属性将添加到从这个原型中继承属性的所有对象的中。例如,可以通过如下的语句向所有雇员中添加 <code>specialty</code> 属性:</p>
+
+<pre class="brush: js notranslate">Employee.prototype.specialty = "none";
+</pre>
+
+<p>只要 JavaScript 执行了该语句,则 <code>mark</code> 对象也将具有 <code>specialty</code> 属性,其值为 <code>"none"</code>。下图则表示了在 <code>Employee</code> 原型中添加该属性,然后在 <code>Engineer</code> 的原型中重载该属性的效果。</p>
+
+<p><img alt="" class="internal" src="/@api/deki/files/4422/=figure8.4.png" style="height: 519px; width: 833px;"><br>
+ <small><strong>添加属性</strong></small></p>
+
+<h2 id="more_flexible_constructors" name="more_flexible_constructors">更灵活的构造器</h2>
+
+<p>到目前为止,本文所展示的构造函数都不能让你在创建新实例时为其制定属性值。其实我们也可以像 Java 一样,为构造器提供参数以初始化实例的属性值。下图展示了一种实现方式。</p>
+
+<p><img alt="" class="internal" id="figure8.5" src="/@api/deki/files/4423/=figure8.5.png" style="height: 481px; width: 1012px;"><br>
+ <small><strong>Specifying properties in a constructor, take 1</strong></small></p>
+
+<p>下面的表格中罗列了这些对象在 Java 和 JavaScript 中的定义。</p>
+
+<table class="standard-table">
+ <thead>
+ <tr>
+ <th scope="col">JavaScript</th>
+ <th scope="col">Java</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>
+ <pre class="brush: js notranslate">
+function Employee (name, dept) {
+ this.name = name || "";
+ this.dept = dept || "general";
+}
+</pre>
+ </td>
+ <td>
+ <pre class="brush: java notranslate">
+public class Employee {
+ public String name;
+ public String dept;
+ public Employee () {
+ this("", "general");
+ }
+ public Employee (String name) {
+ this(name, "general");
+ }
+ public Employee (String name, String dept) {
+ this.name = name;
+ this.dept = dept;
+ }
+}
+</pre>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <pre class="brush: js notranslate">
+function WorkerBee (projs) {
+ this.projects = projs || [];
+}
+WorkerBee.prototype = new Employee;
+</pre>
+ </td>
+ <td>
+ <pre class="brush: java notranslate">
+public class WorkerBee extends Employee {
+ public String[] projects;
+ public WorkerBee () {
+ this(new String[0]);
+ }
+ public WorkerBee (String[] projs) {
+ projects = projs;
+ }
+}
+
+</pre>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <pre class="brush: js notranslate">
+
+function Engineer (mach) {
+ this.dept = "engineering";
+ this.machine = mach || "";
+}
+Engineer.prototype = new WorkerBee;
+</pre>
+ </td>
+ <td>
+ <pre class="brush: java notranslate">
+public class Engineer extends WorkerBee {
+ public String machine;
+ public Engineer () {
+ dept = "engineering";
+ machine = "";
+ }
+ public Engineer (String mach) {
+ dept = "engineering";
+ machine = mach;
+ }
+}
+</pre>
+ </td>
+ </tr>
+ </tbody>
+</table>
+
+<p>上面使用 JavaScript 定义过程使用了一种设置默认值的特殊惯用法:</p>
+
+<pre class="brush: js notranslate">this.name = name || "";
+</pre>
+
+<p>JavaScript 的逻辑或操作符(<code>||</code>)会对第一个参数进行判断。如果该参数值运算后结果为真,则操作符返回该值。否则,操作符返回第二个参数的值。因此,这行代码首先检查 <code>name</code> 是否是对<code>name</code> 属性有效的值。如果是,则设置其为 <code>this.name</code> 的值。否则,设置 <code>this.name</code> 的值为空的字符串。尽管这种用法乍看起来有些费解,为了简洁起见,本章将使用这种习惯用法。</p>
+
+<div class="note">
+<p><strong>提示:</strong>如果调用构造函数时,指定了可以转换为 <code><code>false</code></code> 的参数(比如<code>0</code>和空字符串),结果可能出乎调用者意料。此时,将使用默认值(译注:不是指定的参数值 0 和 "")。</p>
+</div>
+
+<p>使用这些定义,当创建对象的实例时,可以为本地定义的属性指定值。你可以使用以下语句创建一个新的<code>Engineer</code>:</p>
+
+<pre class="brush: js notranslate">var jane = new Engineer("belau");
+</pre>
+
+<p>此时,<code>Jane</code> 的属性如下所示:</p>
+
+<pre class="brush: js notranslate">jane.name == "";
+jane.dept == "engineering";
+jane.projects == [];
+jane.machine == "belau"
+</pre>
+
+<p>注意,由上面对类的定义,您无法为诸如 <code>name</code> 这样的继承属性指定初始值。如果想在 JavaScript 中为继承的属性指定初始值,您需要在构造函数中添加更多的代码。</p>
+
+<p>到目前为止,构造函数已经能够创建一个普通对象,然后为新对象指定本地的属性和属性值。您还可以通过直接调用原型链上的更高层次对象的构造函数,让构造器添加更多的属性。下图即实现了这一功能。</p>
+
+<p><img alt="" class="internal" src="/@api/deki/files/4430/=figure8.6.png" style="height: 534px; width: 1063px;"><br>
+ <small><strong>Specifying properties in a constructor, take 2</strong></small></p>
+
+<p>我们来详细看一下这些定义。这是<code>Engineer</code>构造函数的新定义:</p>
+
+<pre class="brush: js notranslate">function Engineer (name, projs, mach) {
+ this.base = WorkerBee;
+ this.base(name, "engineering", projs);
+ this.machine = mach || "";
+}
+</pre>
+
+<p>假设您创建了一个新的 <code>Engineer</code> 对象,如下所示:</p>
+
+<pre class="brush: js notranslate">var jane = new Engineer("Doe, Jane", ["navigator", "javascript"], "belau");
+</pre>
+
+<p>JavaScript 会按以下步骤执行:</p>
+
+<ol>
+ <li><code>new</code> 操作符创建了一个新的对象,并将其 <code>__proto__</code> 属性设置为 <code>Engineer.prototype</code>。</li>
+ <li><code>new</code> 操作符将该新对象作为 <code>this</code> 的值传递给 <code>Engineer</code> 构造函数。</li>
+ <li>构造函数为该新对象创建了一个名为 <code>base</code> 的新属性,并指向 <code>WorkerBee</code> 的构造函数。这使得 <code>WorkerBee</code> 构造函数成为 <code>Engineer</code> 对象的一个方法。<code>base</code> 属性的名称并没有什么特殊性,我们可以使用任何其他合法的名称来代替;<code>base</code> 仅仅是为了贴近它的用意。</li>
+ <li>
+ <p>构造函数调用 <code>base</code> 方法,将传递给该构造函数的参数中的两个,作为参数传递给 <code>base</code> 方法,同时还传递一个字符串参数  <code>"engineering"。显式地在构造函数中使用</code> <code>"engineering"</code> 表明所有 <code>Engineer</code> 对象继承的 <code>dept</code> 属性具有相同的值,且该值重载了继承自 <code>Employee</code> 的值。</p>
+ </li>
+ <li>
+ <p>因为 <code>base</code> 是 <code>Engineer</code> 的一个方法,在调用 <code>base</code> 时,JavaScript 将在步骤 1 中创建的对象绑定给 <code>this</code> 关键字。这样,<code>WorkerBee</code> 函数接着将 <code>"Doe, Jane"</code> 和 <code>"engineering"</code> 参数传递给 <code>Employee</code> 构造函数。当从 <code>Employee</code> 构造函数返回时,<code>WorkerBee</code> 函数用剩下的参数设置 <code>projects</code> 属性。</p>
+ </li>
+ <li>当从 <code>base</code> 方法返回后,<code>Engineer</code> 构造函数将对象的 <code>machine</code> 属性初始化为 <code>"belau"</code>。</li>
+ <li>当从构造函数返回时,JavaScript 将新对象赋值给 <code>jane</code> 变量。</li>
+</ol>
+
+<p>你可以认为,在 <code>Engineer</code> 的构造器中调用了 <code>WorkerBee</code> 的构造器,也就为 <code>Engineer</code> 对象设置好了继承关系。事实并非如此。调用 <code>WorkerBee</code> 构造器确保了<code>Engineer</code> 对象以所有在构造器中所指定的属性被调用。但是,如果后续在 <code>Employee</code> 或者 <code>WorkerBee</code> 原型中添加了属性,那些属性不会被 <code>Engineer</code> 对象继承。例如,假设如下语句:</p>
+
+<pre class="brush: js notranslate">function Engineer (name, projs, mach) {
+ this.base = WorkerBee;
+ this.base(name, "engineering", projs);
+ this.machine = mach || "";
+}
+var jane = new Engineer("Doe, Jane", ["navigator", "javascript"], "belau");
+Employee.prototype.specialty = "none";
+</pre>
+
+<p>对象 <code>jane</code> 不会继承 <code>specialty</code> 属性。您必须显式地设置原型才能确保动态的继承。如果修改成如下的语句:</p>
+
+<pre class="brush: js notranslate">function Engineer (name, projs, mach) {
+ this.base = WorkerBee;
+ this.base(name, "engineering", projs);
+ this.machine = mach || "";
+}
+Engineer.prototype = new WorkerBee;
+var jane = new Engineer("Doe, Jane", ["navigator", "javascript"], "belau");
+Employee.prototype.specialty = "none";
+</pre>
+
+<p>现在 <code>jane</code> 对象的 <code>specialty</code> 属性为 "none" 了。</p>
+
+<p>继承的另一种途径是使用<a href="/zh-CN/docs/JavaScript/Reference/Global_Objects/Function/call" title="en-US/docs/JavaScript/Reference/Global Objects/Function/call"><code>call()</code></a> / <a href="/zh-CN/docs/JavaScript/Reference/Global_Objects/Function/apply" title="en-US/docs/JavaScript/Reference/Global Objects/Function/apply"><code>apply()</code></a> 方法。下面的方式都是等价的:</p>
+
+<table>
+ <tbody>
+ <tr>
+ <td>
+ <pre class="brush: js notranslate">
+function Engineer (name, projs, mach) {
+ this.base = WorkerBee;
+ this.base(name, "engineering", projs);
+ this.machine = mach || "";
+}
+</pre>
+ </td>
+ <td>
+ <pre class="brush: js notranslate">
+function Engineer (name, projs, mach) {
+ WorkerBee.call(this, name, "engineering", projs);
+ this.machine = mach || "";
+}
+</pre>
+ </td>
+ </tr>
+ </tbody>
+</table>
+
+<p>使用 javascript 的 <code>call()</code> 方法相对明了一些,因为无需 <code>base</code> 方法了。</p>
+
+<h2 id="再谈属性的继承">再谈属性的继承</h2>
+
+<p>前面的小节中描述了 JavaScript 构造器和原型如何提供层级结构和继承的实现。本节中对之前未讨论的一些细节进行阐述。</p>
+
+<h3 id="本地值和继承值">本地值和继承值</h3>
+
+<p>正如本章前面所述,在访问一个对象的属性时,JavaScript 将执行下面的步骤:</p>
+
+<ol>
+ <li>检查对象自身是否存在。如果存在,返回值。</li>
+ <li>如果本地值不存在,检查原型链(通过 <code>__proto__</code> 属性)。</li>
+ <li>如果原型链中的某个对象具有指定属性,则返回值。</li>
+ <li>如果这样的属性不存在,则对象没有该属性,返回 undefined。</li>
+</ol>
+
+<p>以上步骤的结果依赖于你是如何定义的。最早的例子中有如下定义:</p>
+
+<pre class="brush: js notranslate">function Employee () {
+ this.name = "";
+ this.dept = "general";
+}
+
+function WorkerBee () {
+ this.projects = [];
+}
+WorkerBee.prototype = new Employee;
+</pre>
+
+<p>基于这些定义,假定通过如下的语句创建 <code>WorkerBee</code> 的实例 <code>amy</code>:</p>
+
+<pre class="brush: js notranslate">var amy = new WorkerBee;
+</pre>
+
+<p>则 <code>amy</code> 对象将具有一个本地属性 <code>projects</code>。<code>name</code>和 <code>dept</code> 则不是 <code>amy</code> 对象的本地属性,而是从 <code>amy</code> 对象的 <code>__proto__</code> 属性获得的。因此,<code>amy</code> 将具有如下的属性值:</p>
+
+<pre class="brush: js notranslate">amy.name == "";
+amy.dept == "general";
+amy.projects == [];
+</pre>
+
+<p>现在,假设修改了与 <code>Employee</code> 的相关联原型中的 <code>name</code> 属性的值:</p>
+
+<pre class="brush: js notranslate">Employee.prototype.name = "Unknown"
+</pre>
+
+<p>乍一看,你可能觉得新的值会传播给所有 <code>Employee</code> 的实例。然而,并非如此。</p>
+
+<p>在创建 <code>Employee</code> 对象的<em>任意</em>实例时,该实例的 <code>name</code> 属性将获得一个<strong>本地值</strong>(空的字符串)。这就意味着在创建一个新的 <code>Employee</code> 对象作为 <code>WorkerBee</code> 的原型时,<code>WorkerBee.prototype</code> 的 <code>name</code> 属性将具有一个本地值。因此,当 JavaScript 查找 <code>amy</code> 对象(<code>WorkerBee</code> 的实例)的 <code>name</code> 属性时,JavaScript 将找到 <code>WorkerBee.prototype</code> 中的本地值。因此,也就不会继续在原型链中向上找到 <code>Employee.prototype</code> 了。</p>
+
+<p>如果想在运行时修改一个对象的属性值并且希望该值被所有该对象的后代所继承,您就不能在该对象的构造器函数中定义该属性。而应该将该属性添加到该对象所关联的原型中。例如,假设将前面的代码作如下修改:</p>
+
+<pre class="brush: js notranslate">function Employee () {
+ this.dept = "general";
+}
+Employee.prototype.name = "";
+
+function WorkerBee () {
+ this.projects = [];
+}
+WorkerBee.prototype = new Employee;
+
+var amy = new WorkerBee;
+
+Employee.prototype.name = "Unknown";
+</pre>
+
+<p>在这种情况下,<code>amy</code> 的 <code>name</code> 属性将为 "Unknown"。</p>
+
+<p>正如这些例子所示,如果希望对象的属性具有默认值,并且希望在运行时修改这些默认值,应该在对象的原型中设置这些属性,而不是在构造器函数中。</p>
+
+<h3 id="判断实例的关系">判断实例的关系</h3>
+
+<p>JavaScript 的属性查找机制首先在对象自身的属性中查找,如果指定的属性名称没有找到,将在对象的特殊属性 <code>__proto__</code> 中查找。这个过程是递归的;被称为“在原型链中查找”。</p>
+
+<p>特殊的 <code>__proto__</code> 属性是在构建对象时设置的;设置为构造器的 <code>prototype</code> 属性的值。所以表达式 <code>new Foo()</code> 将创建一个对象,其 <code>__proto__ == <code class="moz-txt-verticalline">Foo.prototype</code></code>。因而,修改 <code class="moz-txt-verticalline">Foo.prototype</code> 的属性,将改变所有通过 <code>new Foo()</code> 创建的对象的属性的查找。</p>
+
+<p>每个对象都有一个 <code>__proto__</code> 对象属性(除了 <code>Object);每个函数都有一个</code> <code>prototype</code> 对象属性。因此,通过“原型继承”,对象与其它对象之间形成关系。通过比较对象的 <code>__proto__</code> 属性和函数的 <code>prototype</code> 属性可以检测对象的继承关系。JavaScript 提供了便捷方法:<code>instanceof</code> 操作符可以用来将一个对象和一个函数做检测,如果对象继承自函数的原型,则该操作符返回真。例如:</p>
+
+<pre class="brush: js notranslate">var f = new Foo();
+var isTrue = (f instanceof Foo);</pre>
+
+<p>作为详细一点的例子,假定我们使用和在 <a href="#Inheriting_properties">Inheriting properties</a> 中相同的一组定义。创建 <code>Engineer</code> 对象如下:</p>
+
+<pre class="brush: js notranslate">var chris = new Engineer("Pigman, Chris", ["jsd"], "fiji");
+</pre>
+
+<p>对于该对象,以下所有语句均为真:</p>
+
+<pre class="brush: js notranslate">chris.__proto__ == Engineer.prototype;
+chris.__proto__.__proto__ == WorkerBee.prototype;
+chris.__proto__.__proto__.__proto__ == Employee.prototype;
+chris.__proto__.__proto__.__proto__.__proto__ == Object.prototype;
+chris.__proto__.__proto__.__proto__.__proto__.__proto__ == null;
+</pre>
+
+<p>基于此,可以写出一个如下所示的 <code>instanceOf</code> 函数:</p>
+
+<pre class="brush: js notranslate">function instanceOf(object, constructor) {
+ while (object != null) {
+ if (object == constructor.prototype)
+ return true;
+ if (typeof object == 'xml') {
+ return constructor.prototype == XML.prototype;
+ }
+ object = object.__proto__;
+ }
+ return false;
+}
+</pre>
+
+<div class="note"><strong>Note:</strong> 在上面的实现中,检查对象的类型是否为 "xml" 的目的在于解决新近版本的 JavaScript 中表达 XML 对象的特异之处。如果您想了解其中琐碎细节,可以参考 {{ bug(634150) }}。</div>
+
+<div>使用上面定义的 instanceOf 函数,这些表达式为真:</div>
+
+<div></div>
+
+<pre class="brush: js notranslate">instanceOf (chris, Engineer)
+instanceOf (chris, WorkerBee)
+instanceOf (chris, Employee)
+instanceOf (chris, Object)
+</pre>
+
+<p>但如下表达式为假:</p>
+
+<pre class="brush: js notranslate">instanceOf (chris, SalesPerson)</pre>
+
+<h3 id="构造器中的全局信息">构造器中的全局信息</h3>
+
+<p>在创建构造器时,在构造器中设置全局信息要小心。例如,假设希望为每一个雇员分配一个唯一标识。可能会为 <code>Employee</code> 使用如下定义:</p>
+
+<pre class="brush: js notranslate">var idCounter = 1;
+
+function Employee (name, dept) {
+ this.name = name || "";
+ this.dept = dept || "general";
+ this.id = idCounter++;
+}
+</pre>
+
+<p>基于该定义,在创建新的 <code>Employee</code> 时,构造器为其分配了序列中的下一个标识符。然后递增全局的标识符计数器。因此,如果,如果随后的语句如下,则 <code>victoria.id</code> 为 1 而 <code>harry.id</code> 为 2:</p>
+
+<pre class="brush: js notranslate">var victoria = new Employee("Pigbert, Victoria", "pubs")
+var harry = new Employee("Tschopik, Harry", "sales")
+</pre>
+
+<p>乍一看似乎没问题。但是,无论什么目的,在每一次创建 <code>Employee</code> 对象时,<code>idCounter</code> 都将被递增一次。如果创建本章中所描述的整个 <code>Employee</code> 层级结构,每次设置原型的时候,<code>Employee</code> 构造器都将被调用一次。假设有如下代码:</p>
+
+<pre class="brush: js notranslate">var idCounter = 1;
+
+function Employee (name, dept) {
+ this.name = name || "";
+ this.dept = dept || "general";
+ this.id = idCounter++;
+}
+
+function Manager (name, dept, reports) {...}
+Manager.prototype = new Employee;
+
+function WorkerBee (name, dept, projs) {...}
+WorkerBee.prototype = new Employee;
+
+function Engineer (name, projs, mach) {...}
+Engineer.prototype = new WorkerBee;
+
+function SalesPerson (name, projs, quota) {...}
+SalesPerson.prototype = new WorkerBee;
+
+var mac = new Engineer("Wood, Mac");
+</pre>
+
+<p>还可以进一步假设上面省略掉的定义中包含 <code>base</code> 属性而且调用了原型链中高于它们的构造器。即便在现在这个情况下,在 <code>mac</code> 对象创建时,<code>mac.id</code> 为 5。</p>
+
+<p>依赖于应用程序,计数器额外的递增可能有问题,也可能没问题。如果确实需要准确的计数器,则以下构造器可以作为一个可行的方案:</p>
+
+<pre class="brush: js notranslate">function Employee (name, dept) {
+ this.name = name || "";
+ this.dept = dept || "general";
+ if (name)
+ this.id = idCounter++;
+}
+</pre>
+
+<p>在用作原型而创建新的 <code>Employee</code> 实例时,不会指定参数。使用这个构造器定义,如果不指定参数,构造器不会指定标识符,也不会递增计数器。而如果想让 <code>Employee</code> 分配到标识符,则必需为雇员指定姓名。在这个例子中,<code>mac.id</code> 将为 1。</p>
+
+<p>或者,您可以创建一个 Employee 的原型对象的副本以分配给 WorkerBee:</p>
+
+<pre class="brush: js notranslate">WorkerBee.prototype = Object.create(Employee.prototype);
+// instead of WorkerBee.prototype = new Employee</pre>
+
+<h3 id="没有多重继承">没有多重继承</h3>
+
+<p>某些面向对象语言支持多重继承。也就是说,对象可以从无关的多个父对象中继承属性和属性值。JavaScript 不支持多重继承。</p>
+
+<p>JavaScript 属性值的继承是在运行时通过检索对象的原型链来实现的。因为对象只有一个原型与之关联,所以 JavaScript 无法动态地从多个原型链中继承。</p>
+
+<p>在 JavaScript 中,可以在构造器函数中调用多个其它的构造器函数。这一点造成了多重继承的假象。例如,考虑如下语句:</p>
+
+<pre class="brush: js notranslate">function Hobbyist (hobby) {
+ this.hobby = hobby || "scuba";
+}
+
+function Engineer (name, projs, mach, hobby) {
+ this.base1 = WorkerBee;
+ this.base1(name, "engineering", projs);
+ this.base2 = Hobbyist;
+ this.base2(hobby);
+ this.machine = mach || "";
+}
+Engineer.prototype = new WorkerBee;
+
+var dennis = new Engineer("Doe, Dennis", ["collabra"], "hugo")
+</pre>
+
+<p>进一步假设使用本章前面所属的 <code>WorkerBee</code> 的定义。此时 <code>dennis</code> 对象具有如下属性:</p>
+
+<pre class="brush: js notranslate">dennis.name == "Doe, Dennis"
+dennis.dept == "engineering"
+dennis.projects == ["collabra"]
+dennis.machine == "hugo"
+dennis.hobby == "scuba"
+</pre>
+
+<p><code>dennis</code> 确实从 <code>Hobbyist</code> 构造器中获得了 <code>hobby</code> 属性。但是,假设添加了一个属性到 <code>Hobbyist</code> 构造器的原型:</p>
+
+<pre class="brush: js notranslate">Hobbyist.prototype.equipment = ["mask", "fins", "regulator", "bcd"]
+</pre>
+
+<p><code>dennis</code> 对象不会继承这个新属性。</p>
+
+<div>{{ PreviousNext("JavaScript/Guide/Predefined_Core_Objects", "JavaScript/Guide/Inheritance_Revisited") }}</div>
diff --git a/files/zh-cn/web/javascript/guide/expressions_and_operators/index.html b/files/zh-cn/web/javascript/guide/expressions_and_operators/index.html
new file mode 100644
index 0000000000..b7e809269d
--- /dev/null
+++ b/files/zh-cn/web/javascript/guide/expressions_and_operators/index.html
@@ -0,0 +1,984 @@
+---
+title: 表达式与运算符
+slug: Web/JavaScript/Guide/Expressions_and_Operators
+tags:
+ - JavaScript
+ - 入门
+ - 指南
+ - 表达式
+translation_of: Web/JavaScript/Guide/Expressions_and_Operators
+---
+<div>{{jsSidebar("JavaScript Guide")}} {{PreviousNext("Web/JavaScript/Guide/Functions", "Web/JavaScript/Guide/Numbers_and_dates")}}</div>
+
+<p class="summary">本章描述了 JavaScript 的表达式和运算符,包括了赋值,比较,算数,位运算,逻辑,字符串,三元等等。</p>
+
+<p>一个完整详细的运算符列表和表达式可以参见 <a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators">reference</a>.</p>
+
+<h2 id="运算符">运算符</h2>
+
+<p>JavaScript 拥有如下类型的运算符。本节描述了运算符和运算符的优先级。</p>
+
+<ul>
+ <li>{{ web.link("#赋值运算符", "赋值运算符(Assignment operators)") }}</li>
+ <li>{{ web.link("#比较运算符", "比较运算符(Comparison operators)") }}</li>
+ <li>{{ web.link("#算术运算符", "算数运算符(Arithmetic operators)") }}</li>
+ <li>{{ web.link("#位运算符", "位运算符(Bitwise operators)") }}</li>
+ <li>{{ web.link("#逻辑运算符", "逻辑运算符(Logical operators)") }}</li>
+ <li>{{ web.link("#字符串运算符", "字符串运算符(String operators)") }}</li>
+ <li>{{ web.link("#conditional_operator", "条件(三元)运算符(Conditional operator)")}}</li>
+ <li>{{ web.link("#comma_operator", "逗号运算符(Comma operator)")}}</li>
+ <li>{{ web.link("#delete", "一元运算符(Unary operators)")}}</li>
+ <li>{{ web.link("#关系操作符", "关系运算符(Relational operator)")}}</li>
+</ul>
+
+<p>JavaScript 拥有二元和一元运算符, 和一个特殊的三元运算符(条件运算符)。一个二元运算符需要两个操作数,分别在运算符的前面和后面:</p>
+
+<pre class="notranslate"><em>操作数1 运算符 操作数2</em>
+</pre>
+
+<p>例如, <code>3+4</code> 或 <code>x*y</code>。</p>
+
+<p>一个一元运算符需要一个操作数,在运算符前面或后面:</p>
+
+<pre class="notranslate"><em>运算符 操作数</em></pre>
+
+<p>或</p>
+
+<pre class="notranslate"><em>操作数 运算符</em></pre>
+
+<p>例如, <code>x++</code> 或 <code>++x</code>。</p>
+
+<h3 id="赋值运算符">赋值运算符</h3>
+
+<p>一个 <a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/Assignment_Operators">赋值运算符(assignment operator)</a> 将它右边操作数的值赋给它左边的操作数。最简单的赋值运算符是等于(<code>=</code>),它将右边的操作数值赋给左边的操作数。那么 <code>x = y</code> 就是将 y 的值赋给 x。</p>
+
+<p>还有一些复合赋值操作符,它们是下表列出的这些操作的缩写:</p>
+
+<table class="standard-table">
+ <caption>复合赋值运算符</caption>
+ <thead>
+ <tr>
+ <th>名字</th>
+ <th>简写的操作符</th>
+ <th>含义</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Assignment_Operators#Assignment">赋值(Assignment)</a></td>
+ <td><code>x = y</code></td>
+ <td><code>x = y</code></td>
+ </tr>
+ <tr>
+ <td><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Assignment_Operators#Addition_assignment">加法赋值(Addition assignment)</a></td>
+ <td><code>x += y</code></td>
+ <td><code>x = x + y</code></td>
+ </tr>
+ <tr>
+ <td><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Assignment_Operators#Subtraction_assignment">减法赋值(Subtraction assignment)</a></td>
+ <td><code>x -= y</code></td>
+ <td><code>x = x - y</code></td>
+ </tr>
+ <tr>
+ <td><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Assignment_Operators#Multiplication_assignment">乘法赋值(Multiplication assignment)</a></td>
+ <td><code>x *= y</code></td>
+ <td><code>x = x * y</code></td>
+ </tr>
+ <tr>
+ <td><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Assignment_Operators#Division_assignment">除法赋值(Division assignment)</a></td>
+ <td><code>x /= y</code></td>
+ <td><code>x = x / y</code></td>
+ </tr>
+ <tr>
+ <td><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Assignment_Operators#Remainder_assignment">求余赋值(Remainder assignment)</a></td>
+ <td><code>x %= y</code></td>
+ <td><code>x = x % y</code></td>
+ </tr>
+ <tr>
+ <td><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Assignment_Operators#Exponentiation_assignment">求幂赋值(Exponentiation assignment)</a></td>
+ <td><code>x **= y</code></td>
+ <td><code>x = x ** y</code></td>
+ </tr>
+ <tr>
+ <td><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Assignment_Operators#Left_shift_assignment">左移位赋值(Left shift assignment)</a></td>
+ <td><code>x &lt;&lt;= y</code></td>
+ <td><code>x = x &lt;&lt; y</code></td>
+ </tr>
+ <tr>
+ <td><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Assignment_Operators#Right_shift_assignment">右移位赋值(Right shift assignment)</a></td>
+ <td><code>x &gt;&gt;= y</code></td>
+ <td><code>x = x &gt;&gt; y</code></td>
+ </tr>
+ <tr>
+ <td><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Assignment_Operators#Unsigned_right_shift_assignment">无符号右移位赋值(Unsigned right shift assignment)</a></td>
+ <td><code>x &gt;&gt;&gt;= y</code></td>
+ <td><code>x = x &gt;&gt;&gt; y</code></td>
+ </tr>
+ <tr>
+ <td><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Assignment_Operators#Bitwise_AND_assignment">按位与赋值(Bitwise AND assignment)</a></td>
+ <td><code>x &amp;= y</code></td>
+ <td><code>x = x &amp; y</code></td>
+ </tr>
+ <tr>
+ <td><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Assignment_Operators#Bitwise_XOR_assignment">按位异或赋值(Bitwise XOR assignment)</a></td>
+ <td><code>x ^= y</code></td>
+ <td><code>x = x ^ y</code></td>
+ </tr>
+ <tr>
+ <td><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Assignment_Operators#Bitwise_OR_assignment">按位或赋值(Bitwise OR assignment)</a></td>
+ <td><code>x |= y</code></td>
+ <td><code>x = x | y</code></td>
+ </tr>
+ </tbody>
+</table>
+
+<h4 id="解构">解构</h4>
+
+<p>对于更复杂的赋值,<a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment">解构赋值</a>语法是一个能从数组或对象对应的数组结构或对象字面量里提取数据的 Javascript 表达式。</p>
+
+<pre class="brush: js line-numbers language-js notranslate"><code class="language-js"><span class="keyword token">var</span> foo <span class="operator token">=</span> <span class="punctuation token">[</span><span class="string token">"one"</span><span class="punctuation token">,</span> <span class="string token">"two"</span><span class="punctuation token">,</span> <span class="string token">"three"</span><span class="punctuation token">]</span><span class="punctuation token">;</span>
+
+<span class="comment token">// 不使用解构</span>
+<span class="keyword token">var</span> one <span class="operator token">=</span> foo<span class="punctuation token">[</span><span class="number token">0</span><span class="punctuation token">]</span><span class="punctuation token">;</span>
+<span class="keyword token">var</span> two <span class="operator token">=</span> foo<span class="punctuation token">[</span><span class="number token">1</span><span class="punctuation token">]</span><span class="punctuation token">;</span>
+<span class="keyword token">var</span> three <span class="operator token">=</span> foo<span class="punctuation token">[</span><span class="number token">2</span><span class="punctuation token">]</span><span class="punctuation token">;</span>
+
+<span class="comment token">// 使用解构</span>
+<span class="keyword token">var</span> <span class="punctuation token">[</span>one<span class="punctuation token">,</span> two<span class="punctuation token">,</span> three<span class="punctuation token">]</span> <span class="operator token">=</span> foo<span class="punctuation token">;</span></code></pre>
+
+<h3 id="比较运算符">比较运算符</h3>
+
+<p><a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/Comparison_Operators">比较运算符</a>比较它的操作数并返回一个基于表达式是否为真的逻辑值。操作数可以是数字,字符串,逻辑,对象值。字符串比较是基于标准的字典顺序,使用Unicode值。在多数情况下,如果两个操作数不是相同的类型, JavaScript 会尝试转换它们为恰当的类型来比较。这种行为通常发生在数字作为操作数的比较。类型转换的例外是使用 <code>===</code> 和 <code>!==</code> 操作符,它们会执行严格的相等和不相等比较。这些运算符不会在检查相等之前转换操作数的类型。下面的表格描述了该示例代码中的各比较运算符</p>
+
+<pre class="brush: js line-numbers language-js notranslate"><code class="language-js"><span class="keyword token">var</span> var1 <span class="operator token">=</span> <span class="number token">3;
+</span>var var2 <span class="operator token">=</span> <span class="number token">4</span><span class="punctuation token">;</span></code></pre>
+
+<table class="standard-table">
+ <caption>比较运算符</caption>
+ <thead>
+ <tr>
+ <th scope="col">运算符</th>
+ <th scope="col">描述</th>
+ <th scope="col">返回true的示例</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Comparison_Operators#Equality">等于 Equal</a> (<code>==</code>)</td>
+ <td>
+ <p>如果两边操作数相等时返回true。</p>
+ </td>
+ <td><code>3 == var1</code>
+ <p><code>"3" == var1</code></p>
+ <code>3 == '3'</code></td>
+ </tr>
+ <tr>
+ <td><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Comparison_Operators#Inequality">不等于 Not equal</a> (<code>!=</code>)</td>
+ <td>如果两边操作数不相等时返回true</td>
+ <td><code>var1 != 4<br>
+ var2 != "3"</code></td>
+ </tr>
+ <tr>
+ <td><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Comparison_Operators#Identity">全等 Strict equal</a> (<code>===</code>)</td>
+ <td>两边操作数相等且类型相同时返回true。 参见 {{jsxref("Object.is")}} and <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Equality_comparisons_and_sameness" title="/en-US/docs/Web/JavaScript/Guide/Sameness">sameness in JS</a>.</td>
+ <td><code>3 === var1</code></td>
+ </tr>
+ <tr>
+ <td><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Comparison_Operators#Nonidentity">不全等 Strict not equal</a> (<code>!==</code>)</td>
+ <td>两边操作数不相等或类型不同时返回true。</td>
+ <td><code>var1 !== "3"<br>
+ 3 !== '3'</code></td>
+ </tr>
+ <tr>
+ <td><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Comparison_Operators#Greater_than_operator">大于 Greater than</a> (<code>&gt;</code>)</td>
+ <td>左边的操作数大于右边的操作数返回true</td>
+ <td><code>var2 &gt; var1<br>
+ "12" &gt; 2</code></td>
+ </tr>
+ <tr>
+ <td><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Comparison_Operators#Greater_than_or_equal_operator">大于等于 Greater than or equal</a> (<code>&gt;=</code>)</td>
+ <td>左边的操作数大于或等于右边的操作数返回true</td>
+ <td><code>var2 &gt;= var1<br>
+ var1 &gt;= 3</code></td>
+ </tr>
+ <tr>
+ <td><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Comparison_Operators#Less_than_operator">小于 Less than</a> (<code>&lt;</code>)</td>
+ <td>左边的操作数小于右边的操作数返回true</td>
+ <td><code>var1 &lt; var2<br>
+ "2" &lt; 12</code></td>
+ </tr>
+ <tr>
+ <td><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Comparison_Operators#Less_than_or_equal_operator">小于等于 Less than or equal</a> (<code>&lt;=</code>)</td>
+ <td>左边的操作数小于或等于右边的操作数返回true</td>
+ <td><code>var1 &lt;= var2<br>
+ var2 &lt;= 5</code></td>
+ </tr>
+ </tbody>
+</table>
+
+<div class="note">
+<p><strong>注意: </strong>(<strong>=&gt;</strong>) 不是运算符,而是<a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions">箭头函数</a>的标记符号 。</p>
+</div>
+
+<h3 id="算术运算符">算术运算符</h3>
+
+<p>算术运算符使用数值(字面量或者变量)作为操作数并返回一个数值.标准的算术运算符就是加减乘除(+ - * /)。当操作数是浮点数时,这些运算符表现得跟它们在大多数编程语言中一样(特殊要注意的是,除零会产生{{jsxref("Infinity")}})。<span style="line-height: 1.5;">例如:</span></p>
+
+<pre class="brush: js notranslate">1 / 2; // 0.5
+1 / 2 == 1.0 / 2.0; // true
+</pre>
+
+<p>除了标准的算术运算符(+, - ,* /),JavaScript还提供了下表中的算术运算符。</p>
+
+<table class="fullwidth-table" style="height: 469px; width: 520px;">
+ <caption>表 3.3 算术运算符</caption>
+ <thead>
+ <tr>
+ <th scope="col">Operator</th>
+ <th scope="col">Description</th>
+ <th scope="col">Example</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>求余(<code>%</code>)</td>
+ <td>二元运算符. 返回相除之后的余数.</td>
+ <td>12 % 5 返回 2。</td>
+ </tr>
+ <tr>
+ <td>自增(<code>++</code>)</td>
+ <td>一元运算符. 将操作数的值加一. 如果放在操作数前面 (<code>++x</code>), 则返回加一后的值; 如果放在操作数后面 (<code>x++</code>), 则返回操作数原值,然后再将操作数加一.</td>
+ <td>
+ <p><code>var x=3; </code></p>
+
+ <p><code>console.log(++x); //4</code></p>
+
+ <p><code>console.log(x); //4</code></p>
+
+ <p><code>var y=3;</code></p>
+
+ <p><code>console.log(y++); //3</code></p>
+
+ <p><code>console.log(y); //4</code></p>
+ </td>
+ </tr>
+ <tr>
+ <td>自减(<code>--</code>)</td>
+ <td>一元运算符. 将操作数的值减一. 前后缀两种用法的返回值类似自增运算符.</td>
+ <td>
+ <p>var x=3; console.log(--x); //输入2,x=2</p>
+
+ <p>var y=3;console.log(y--);//输出3,x=2;</p>
+ </td>
+ </tr>
+ <tr>
+ <td>一元负值符(<code>-</code>)</td>
+ <td>一元运算符,返回操作数的负值.</td>
+ <td>
+ <p>var x=3; console.log(-x); //输入-3</p>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <p>一元正值符(+)</p>
+ </td>
+ <td>一元运算符, 如果操作数在之前不是number,试图将其转换为number</td>
+ <td>
+ <p><code>console.log( +'3' ); // 3</code></p>
+
+ <p><code>console.log( '3' ); // '3'</code></p>
+
+ <p>console.log(+true); // 1</p>
+ </td>
+ </tr>
+ <tr>
+ <td>指数运算符(**)</td>
+ <td>计算 <code>base(底数)</code> 的 <code>exponent(</code>指数<code>)次方</code>, 表示为<code>base<sup>exponent</sup></code></td>
+ <td>
+ <p><code>2 ** 3</code> returns <code>8</code>.<br>
+ <code>10 ** -1</code> returns <code>0.1</code>.</p>
+ </td>
+ </tr>
+ <tr>
+ </tr>
+ </tbody>
+</table>
+
+<h3 id="位运算符">位运算符</h3>
+
+<p>位运算符将它的操作数视为32位元的二进制串(0和1组成)而非十进制八进制或十六进制数。例如:十进制数字9用二进制表示为1001,位运算符就是在这个二进制表示上执行运算,但是返回结果是标准的JavaScript数值。</p>
+
+<p>下表总结了 JavaScript 的位运算符。</p>
+
+<table class="standard-table">
+ <caption>位运算符</caption>
+ <thead>
+ <tr>
+ <th scope="col">Operator</th>
+ <th scope="col">Usage</th>
+ <th scope="col">Description</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>按位与<a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators#Bitwise_AND"> AND</a></td>
+ <td><code>a &amp; b</code></td>
+ <td>
+ <p>在a,b的位表示中,每一个对应的位都为1则返回1, 否则返回0.</p>
+ </td>
+ </tr>
+ <tr>
+ <td>按位或<a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators#Bitwise_OR"> OR</a></td>
+ <td><code>a | b</code></td>
+ <td>在a,b的位表示中,每一个对应的位,只要有一个为1则返回1, 否则返回0.</td>
+ </tr>
+ <tr>
+ <td>按位异或<a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators#Bitwise_XOR"> XOR</a></td>
+ <td><code>a ^ b</code></td>
+ <td>在a,b的位表示中,每一个对应的位,两个不相同则返回1,相同则返回0.</td>
+ </tr>
+ <tr>
+ <td>按位非<a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators#Bitwise_NOT"> NOT</a></td>
+ <td><code>~ a</code></td>
+ <td>反转被操作数的位。</td>
+ </tr>
+ <tr>
+ <td>左移<a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators#Left_shift"> shift</a></td>
+ <td><code>a &lt;&lt; b</code></td>
+ <td>将a的二进制串向左移动b位,右边移入0.</td>
+ </tr>
+ <tr>
+ <td>算术右移</td>
+ <td><code>a &gt;&gt; b</code></td>
+ <td>
+ <p>把a的二进制表示向右移动b位,丢弃被移出的所有位.</p>
+
+ <p>(译注:算术右移左边空出的位是根据最高位是0和1来进行填充的)</p>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <p>无符号右移</p>
+
+ <p>(左边空出位用0填充)</p>
+ </td>
+ <td><code>a &gt;&gt;&gt; b</code></td>
+ <td>把a的二进制表示向右移动b位,丢弃被移出的所有位,并把左边空出的位都填充为0</td>
+ </tr>
+ </tbody>
+</table>
+
+<h4 id="Bitwise_Logical_Operators" name="Bitwise_Logical_Operators">位逻辑运算符</h4>
+
+<p>概念上来讲, 位逻辑运算符工作流程如下:</p>
+
+<ul>
+ <li>操作数被转换为32bit整數,以位序列(0和1组成)表示.若超過32bits,則取低位32bit,如下所示:</li>
+</ul>
+
+<dl>
+ <dt>
+ <pre class="notranslate"><code>Before: 11100110111110100000000000000110000000000001
+After: 10100000000000000110000000000001</code></pre>
+ </dt>
+</dl>
+
+<ul>
+ <li>第一个操作数的每一位都与第二个操作数的对应位组对: 第一位对应第一位,第二位对应第二位,以此类推.</li>
+ <li>运算符被应用到每一对"位"上, 最终的运算结果由每一对“位”的运算结果组合起来.</li>
+</ul>
+
+<p>例如,十进制数9的二进制表示是1001,十进制数15的二进制表示是1111.因此,当位运算符应用到这两个值时,结果如下:</p>
+
+<table class="standard-table">
+ <caption>位运算符范例</caption>
+ <thead>
+ <tr>
+ <th scope="col">表达式</th>
+ <th scope="col">结果</th>
+ <th scope="col">二进制描述</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td><code>15 &amp; 9</code></td>
+ <td><code>9</code></td>
+ <td><code>1111 &amp; 1001 = 1001</code></td>
+ </tr>
+ <tr>
+ <td><code>15 | 9</code></td>
+ <td><code>15</code></td>
+ <td><code>1111 | 1001 = 1111</code></td>
+ </tr>
+ <tr>
+ <td><code>15 ^ 9</code></td>
+ <td><code>6</code></td>
+ <td><code>1111 ^ 1001 = 0110</code></td>
+ </tr>
+ <tr>
+ <td><code>~15</code></td>
+ <td><code>-16</code></td>
+ <td><code>~</code><code>00000000...</code><code>00001111 = </code><code>1111</code><code>1111</code><code>...</code><code>11110000</code></td>
+ </tr>
+ <tr>
+ <td><code>~9</code></td>
+ <td><code>-10</code></td>
+ <td><code>~</code><code>00000000</code><code>...</code><code>0000</code><code>1001 = </code><code>1111</code><code>1111</code><code>...</code><code>1111</code><code>0110</code></td>
+ </tr>
+ </tbody>
+</table>
+
+<p>注意位运算符“非”将所有的32位取反,而值的最高位(最左边的一位)为1则表示负数(2-补码表示法)。</p>
+
+<h4 id="Bitwise_Shift_Operators" name="Bitwise_Shift_Operators">移位运算符</h4>
+
+<p><span style="line-height: 1.5;">移位运算符带两个操作数:</span>第一个是待移位的数,第二个是指定第一个数要被移多少位的数。移位的方向由运算符来控制.</p>
+
+<p>移位运算符把操作数转为32bit整数,然后得出一个与待移位数相同种类的值。</p>
+
+<p>移位运算符列表如下。</p>
+
+<p><strong style="font-style: inherit; font-weight: 700;">移位运算符</strong></p>
+
+<table class="standard-table">
+ <thead>
+ <tr>
+ <th scope="col">运算符</th>
+ <th scope="col">描述</th>
+ <th scope="col">范例</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td><code>&lt;&lt;</code><br>
+ (左移位)</td>
+ <td>将第一个操作数向左移动指定数量的位. 左边移出位被抛弃. 左边移出的几位被丢弃.右边多出的空位由0补齐</td>
+ <td><code>9&lt;&lt;2产生36,因为1001移位2比特向左变为100100,它是36。</code></td>
+ </tr>
+ <tr>
+ <td><code>&gt;&gt;</code><br>
+ (带符号右移)</td>
+ <td>将第一个操作数向右移动指定数量的位. 右边移出位被抛弃. 左边多出的空位由原值的最左边数字补齐.</td>
+ <td><code>9&gt;&gt;2产生2,因为1001移位2位向右变为10,其是2。同样,-9&gt;&gt;2产生-3,由于符号被保留。</code></td>
+ </tr>
+ <tr>
+ <td><code>&gt;&gt;&gt;</code><br>
+ (补零右移)</td>
+ <td>将第一个操作数向右移动指定数量的位. 右边移出位被抛弃. 左边多出的空位由0补齐.</td>
+ <td><code>19&gt;&gt;&gt;2</code>产生4,因为10011移位2位向右变为100,它是4。对非负数值,补零右移和带符号右移产生相同结果。</td>
+ </tr>
+ </tbody>
+</table>
+
+<h3 id="逻辑运算符">逻辑运算符</h3>
+
+<p>逻辑运算符常用于布尔(逻辑)值之间; 当操作数都是布尔值时,返回值也是布尔值。 不过实际上<code>&amp;&amp;</code>和<code>||</code>返回的是一个特定的操作数的值,所以当它用于非布尔值的时候,返回值就可能是非布尔值。 逻辑运算符的描述如下。</p>
+
+<p><strong style="font-style: inherit; font-weight: 700;">逻辑运算符</strong></p>
+
+<table class="fullwidth-table" style="height: 190px; width: 1316px;">
+ <thead>
+ <tr>
+ <th scope="col">运算符</th>
+ <th scope="col">范例</th>
+ <th scope="col">描述</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Logical_Operators#Logical_AND">逻辑与</a><code> (&amp;&amp;</code>)</td>
+ <td><code>expr1 &amp;&amp; expr2</code></td>
+ <td>(逻辑与) 如果expr1能被转换为false,那么返回expr1;否则,返回<code>expr2</code>。因此<code>,&amp;&amp;</code>用于布尔值时,当操作数都为true时返回true;否则返回false.</td>
+ </tr>
+ <tr>
+ <td><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Logical_Operators#Logical_OR">逻辑或 </a>(<code>||</code>)</td>
+ <td><code>expr1 || expr2</code></td>
+ <td>(逻辑或) 如果expr1能被转换为true,那么返回expr1;否则,返回<code>expr2</code>。因此,||用于布尔值时,当任何一个操作数为true则返回true;如果操作数都是false则返回false。</td>
+ </tr>
+ <tr>
+ <td><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Logical_Operators#Logical_NOT">逻辑非</a><code> (!)</code></td>
+ <td><code>!expr</code></td>
+ <td>(逻辑非) 如果操作数能够转换为true则返回false;否则返回true。</td>
+ </tr>
+ </tbody>
+</table>
+
+<p>能被转换为<code>false</code>的值有<code>null</code>, <code>0</code>, <code>NaN</code>, 空字符串("")和<code>undefined</code>。(译者注:也可以称作”falsy“)</p>
+
+<p>下面是&amp;&amp;(逻辑"与")操作符的示例。</p>
+
+<pre class="brush: js notranslate">var a1 = true &amp;&amp; true; // t &amp;&amp; t returns true
+var a2 = true &amp;&amp; false; // t &amp;&amp; f returns false
+var a3 = false &amp;&amp; true; // f &amp;&amp; t returns false
+var a4 = false &amp;&amp; (3 == 4); // f &amp;&amp; f returns false
+var a5 = "Cat" &amp;&amp; "Dog"; // t &amp;&amp; t returns Dog
+var a6 = false &amp;&amp; "Cat"; // f &amp;&amp; t returns false
+var a7 = "Cat" &amp;&amp; false; // t &amp;&amp; f returns false
+</pre>
+
+<p>下面是||(逻辑"或")操作符的示例。</p>
+
+<pre class="brush: js notranslate">var o1 = true || true; // t || t returns true
+var o2 = false || true; // f || t returns true
+var o3 = true || false; // t || f returns true
+var o4 = false || (3 == 4); // f || f returns false
+var o5 = "Cat" || "Dog"; // t || t returns Cat
+var o6 = false || "Cat"; // f || t returns Cat
+var o7 = "Cat" || false; // t || f returns Cat
+</pre>
+
+<p>下面是!(逻辑"非")操作符的示例。</p>
+
+<pre class="brush: js notranslate">var n1 = !true; // !t returns false
+var n2 = !false; // !f returns true
+var n3 = !"Cat"; // !t returns false
+</pre>
+
+<h4 id="Short-Circuit_Evaluation" name="Short-Circuit_Evaluation">短路求值</h4>
+
+<p>作为逻辑表达式进行求值是从左到右,它们是为可能的“短路”的出现而使用以下规则进行测试:</p>
+
+<ul>
+ <li><code>false</code> &amp;&amp; <em>anything</em>    // 被短路求值为false</li>
+ <li><code>true</code> || <em>anything</em>       // 被短路求值为true</li>
+</ul>
+
+<p>逻辑的规则,保证这些评估是总是正确的。请注意,上述表达式的<code>anything</code>部分不会被求值,所以这样做不会产生任何副作用。</p>
+
+<h3 id="字符串运算符">字符串运算符</h3>
+
+<p>除了比较操作符,它可以在字符串值中使用,连接操作符(+)连接两个字符串值相连接,返回另一个字符串,它是两个操作数串的结合。</p>
+
+<p>例如,</p>
+
+<pre class="brush: js line-numbers language-js notranslate"><code class="language-js">console<span class="punctuation token">.</span><span class="function token">log</span><span class="punctuation token">(</span><span class="string token">"my "</span> <span class="operator token">+</span> <span class="string token">"string"</span><span class="punctuation token">)</span><span class="punctuation token">;</span> <span class="comment token">// console logs the string "my string".</span></code></pre>
+
+<p>简写操作符 <code>+=</code> 也可以用来拼接字符串,例如:</p>
+
+<pre class="brush: js notranslate"><code>var myString = "alpha";</code>
+
+<code>myString += "bet"; // 返回 "alphabet" </code>
+</pre>
+
+<h3 id="conditional_operator" name="conditional_operator">条件(三元)运算符</h3>
+
+<p><a href="/zh-CN/docs/Web/JavaScript/Reference/Operators/Conditional_Operator">条件运算符</a>是JavaScript中唯一需要三个操作数的运算符。运算的结果根据给定条件在两个值中取其一。语法为:</p>
+
+<pre class="notranslate"><em>条件 </em>?<em> 值1 </em>:<em> 值2</em>
+</pre>
+
+<p>如果<code>条件</code>为真,则结果取<code>值1</code>。否则为<code>值2</code>。你能够在任何允许使用标准运算符的地方使用条件运算符。</p>
+
+<p>例如,</p>
+
+<pre class="brush: js notranslate">var status = (age &gt;= 18) ? "adult" : "minor";
+</pre>
+
+<p>当 <code>age</code> 大于等于18的时候,将“adult”赋值给<code> status</code>;否则将“minor”赋值给 <code>status</code>。</p>
+
+<h3 id="comma_operator" name="comma_operator">逗号操作符</h3>
+
+<p><a href="/zh-CN/docs/Web/JavaScript/Reference/Operators/Comma_Operator">逗号操作符</a>(<code>,</code>)对两个操作数进行求值并返回最终操作数的值。它常常用在 <code>for</code> 循环中,在每次循环时对多个变量进行更新。</p>
+
+<p>例如,假如 <code>a</code> 是一个二维数组,每个维度各有10个元素,以下代码利用逗号操作符来同时改变两个变量的值。这段代码的功能是打印出该二维数组的对角线元素的值:</p>
+
+<pre class="brush: js notranslate">var x = [0,1,2,3,4,5,6,7,8,9]
+var a = [x, x, x, x, x];
+
+for (var i = 0, j = 9; i &lt;= j; i++, j--)
+ console.log('a[' + i + '][' + j + ']= ' + a[i][j]);</pre>
+
+<h3 id="delete" name="delete"><font face="Consolas, Liberation Mono, Courier, monospace">一元</font>操作符</h3>
+
+<p>一元操作符仅对应一个操作数。</p>
+
+<h4 id="delete" name="delete"><code>delete</code></h4>
+
+<p><code><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/delete">delete</a></code>操作符,删除一个对象或一个对象的属性或者一个数组中某一个键值。语法如下:</p>
+
+<pre class="brush: js notranslate">delete objectName;
+delete objectName.property;
+delete objectName[index];
+delete property; // legal only within a with statement
+</pre>
+
+<p><code>objectName</code>是一个对象名,<code>property</code> 是一个已经存在的属性,<code>index</code>是数组中的一个已经存在的键值的索引值。</p>
+
+<p>第四行的形式只在<code><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/with">with</a></code>声明的状态下是合法的, 从对象中删除一个属性。</p>
+
+<p>你能使用 <code>delete</code> 删除各种各样的隐式声明, 但是被<code>var</code>声明的除外。</p>
+
+<p>如果 <code>delete</code> 操作成功,属性或者元素会变成 <code>undefined</code>。如果 <code>delete</code>可行会返回<code>true</code>,如果不成功返回<code>false</code>。</p>
+
+<pre class="brush: js notranslate">x = 42;
+var y = 43;
+myobj = new Number();
+myobj.h = 4; // create property h
+delete x; // returns true (can delete if declared implicitly)
+delete y; // returns false (cannot delete if declared with var)
+delete Math.PI; // returns false (cannot delete predefined properties)
+delete myobj.h; // returns true (can delete user-defined properties)
+delete myobj; // returns true (can delete if declared implicitly)
+</pre>
+
+<h5 id="删除数组元素">删除数组元素</h5>
+
+<p>删除数组中的元素时,数组的长度是不变的,例如删除<code>a[3]</code>, <code>a[4]</code>,<code>a[4]</code><code>和a[3]</code> 仍然存在变成了<code>undefined</code>。</p>
+
+<p><code>delete</code> 删除数组中的一个元素,这个元素就不在数组中了。例如,<code>trees[3]</code>被删除,<code>trees[3]</code> 仍然可寻址并返回<code>undefined</code>。</p>
+
+<pre class="brush: js notranslate">var trees = new Array("redwood", "bay", "cedar", "oak", "maple");
+delete trees[3];
+if (3 in trees) {
+ // 不会被执行
+}
+</pre>
+
+<p>如果想让数组中存在一个元素但是是<code>undefined</code>值,使用<code>undefined</code>关键字而不是<code>delete</code>操作. 如下: <code>trees[3]分配一个undefined</code>,但是这个数组元素仍然存在:</p>
+
+<pre class="brush: js notranslate">var trees = new Array("redwood", "bay", "cedar", "oak", "maple");
+trees[3] = undefined;
+if (3 in trees) {
+ // this gets executed(会被执行)
+}
+</pre>
+
+<h4 id="typeof" name="typeof"><code>typeof</code></h4>
+
+<p><a href="/zh-CN/docs/Web/JavaScript/Reference/Operators/typeof">typeof操作符</a> 可通过下面2种方式使用:</p>
+
+<pre class="brush: js notranslate">typeof operand
+typeof (operand)
+</pre>
+
+<p>typeof 操作符返回一个表示 operand 类型的字符串值。operand 可为字符串、变量、关键词或对象,其类型将被返回。operand 两侧的括号为可选。</p>
+
+<p>假设你定义了如下的变量:</p>
+
+<pre class="brush: js notranslate">var myFun = new Function("5 + 2");
+var shape = "round";
+var size = 1;
+var today = new Date();
+</pre>
+
+<p>typeof 操作符将会返回如下的结果:</p>
+
+<pre class="brush: js notranslate">typeof myFun; // returns "function"
+typeof shape; // returns "string"
+typeof size; // returns "number"
+typeof today; // returns "object"
+typeof dontExist; // returns "undefined"
+</pre>
+
+<p>对于关键词 <code>true</code> 和 <code>null<font face="Open Sans, Arial, sans-serif">, </font></code><code>typeof</code> 操作符将会返回如下结果:</p>
+
+<pre class="brush: js notranslate">typeof true; // returns "boolean"
+typeof null; // returns "object"
+</pre>
+
+<p>对于一个数值或字符串<code><font face="Open Sans, Arial, sans-serif">, </font></code><code>typeof</code> 操作符将会返回如下结果:</p>
+
+<pre class="brush: js notranslate">typeof 62; // returns "number"
+typeof 'Hello world'; // returns "string"
+</pre>
+
+<p>对于属性值,typeof 操作符将会返回属性所包含值的类型:</p>
+
+<pre class="brush: js notranslate">typeof document.lastModified; // returns "string"
+typeof window.length; // returns "number"
+typeof Math.LN2; // returns "number"
+</pre>
+
+<p>对于方法和函数,typeof 操作符将会返回如下结果:</p>
+
+<pre class="brush: js notranslate">typeof blur; // returns "function"
+typeof eval; // returns "function"
+typeof parseInt; // returns "function"
+typeof shape.split; // returns "function"
+</pre>
+
+<p>对于预定义的对象,typeof 操作符将会返回如下结果:</p>
+
+<pre class="brush: js notranslate">typeof Date; // returns "function"
+typeof Function; // returns "function"
+typeof Math; // returns "object"
+typeof Option; // returns "function"
+typeof String; // returns "function"
+</pre>
+
+<h4 id="void" name="void"><code>void</code></h4>
+
+<p>void 运算符运用方法如下:</p>
+
+<pre class="brush: js notranslate">void (expression)
+void expression
+</pre>
+
+<p>void运算符,表明一个运算没有返回值。expression是javaScript表达式,括号中的表达式是一个可选项,当然使用该方式是一种好的形式。</p>
+
+<p>你可以使用void运算符指明一个超文本链接。该表达式是有效的,但是并不会在当前文档中进行加载。</p>
+
+<p>如下创建了一个超链接文本,当用户单击该文本时,不会有任何效果。</p>
+
+<pre class="brush: html line-numbers language-html notranslate"><code class="language-html"><span class="tag token"><span class="tag token"><span class="punctuation token">&lt;</span>a</span> <span class="attr-name token">href</span><span class="attr-value token"><span class="punctuation token">=</span><span class="punctuation token">"</span>javascript:void(0)<span class="punctuation token">"</span></span><span class="punctuation token">&gt;</span></span>Click here to do nothing<span class="tag token"><span class="tag token"><span class="punctuation token">&lt;/</span>a</span><span class="punctuation token">&gt;</span></span></code></pre>
+
+<p>下面的代码创建了一个超链接,当用户单击它时,提交一个表单。</p>
+
+<pre class="brush: html line-numbers language-html notranslate"><code class="language-html"><span class="tag token"><span class="tag token"><span class="punctuation token">&lt;</span>a</span> <span class="attr-name token">href</span><span class="attr-value token"><span class="punctuation token">=</span><span class="punctuation token">"</span>javascript:void(document.form.submit())<span class="punctuation token">"</span></span><span class="punctuation token">&gt;</span></span>
+Click here to submit<span class="tag token"><span class="tag token"><span class="punctuation token">&lt;/</span>a</span><span class="punctuation token">&gt;</span></span></code></pre>
+
+<h3 id="关系操作符">关系操作符</h3>
+
+<p>关系操作符对操作数进行比较,根据比较结果真或假,返回相应的布尔值。</p>
+
+<h4 id="in" name="in"><code>in</code></h4>
+
+<p><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/in"><code>in</code>操作符</a>,如果所指定的<strong>属性</strong>确实存在于所指定的对象中,则会返回<code>true</code>,语法如下:</p>
+
+<pre class="brush: js notranslate">propNameOrNumber in objectName
+</pre>
+
+<p>在这里 <code>propNameOrNumber</code>可以是一个代表着属性名的字符串或者是一个代表着数组索引的数值表达式,而<code>objectName</code>则是一个对象名。</p>
+
+<p>下面的例子是 <code>in</code> 操作的常见用法。</p>
+
+<pre class="brush: js notranslate">// Arrays
+var trees = new Array("redwood", "bay", "cedar", "oak", "maple");
+0 in trees; // returns true
+3 in trees; // returns true
+6 in trees; // returns false
+"bay" in trees; // returns false (you must specify the index number,
+ // not the value at that index)
+"length" in trees; // returns true (length is an Array property)
+
+// Predefined objects
+"PI" in Math; // returns true
+var myString = new String("coral");
+"length" in myString; // returns true
+
+// Custom objects
+var mycar = {make: "Honda", model: "Accord", year: 1998};
+"make" in mycar; // returns true
+"model" in mycar; // returns true
+</pre>
+
+<h4 id="instanceof" name="instanceof"><code>instanceof</code></h4>
+
+<p>如果所判别的对象确实是所指定的类型,则返回<code>true</code>。其语法如下:</p>
+
+<pre class="brush: js notranslate">objectName instanceof objectType
+</pre>
+
+<p><code>objectName</code> 是需要做判别的对象的名称,而<code>objectType</code>是假定的对象的类型, 例如{{jsxref("Date")}}或 {{jsxref("Array")}}.</p>
+
+<p>当你需要确认一个对象在运行时的类型时,可使用<code>instanceof</code>. 例如,需要 catch 异常时,你可以针对抛出异常的类型,来做不同的异常处理。</p>
+
+<p>例如, 下面的代码使用<code>instanceof</code>去判断 <code>theDay</code>是否是一个 <code>Date</code> 对象. <code>因为theDay</code>是一个<code>Date</code>对象, <code>所以if</code>中的代码会执行.</p>
+
+<pre class="brush: js notranslate">var theDay = new Date(1995, 12, 17);
+if (theDay instanceof Date) {
+ // statements to execute
+}
+</pre>
+
+<h3 id="运算符优先级">运算符优先级</h3>
+
+<p>运算符的优先级,用于确定一个表达式的计算顺序。在你不能确定优先级时,可以通过使用括号显式声明运算符的优先级。</p>
+
+<p>下表列出了描述符的优先级,从最高到最低。</p>
+
+<p><strong style="font-style: inherit; font-weight: 700;">运算符优先级</strong></p>
+
+<table class="standard-table">
+ <thead>
+ <tr>
+ <th scope="col">Operator type</th>
+ <th scope="col">Individual operators</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>member</td>
+ <td><code>. []</code></td>
+ </tr>
+ <tr>
+ <td>call / create instance</td>
+ <td><code>() new</code></td>
+ </tr>
+ <tr>
+ <td>negation/increment</td>
+ <td><code>! ~ - + ++ -- typeof void delete</code></td>
+ </tr>
+ <tr>
+ <td>multiply/divide</td>
+ <td><code>* / %</code></td>
+ </tr>
+ <tr>
+ <td>addition/subtraction</td>
+ <td><code>+ -</code></td>
+ </tr>
+ <tr>
+ <td>bitwise shift</td>
+ <td><code>&lt;&lt; &gt;&gt; &gt;&gt;&gt;</code></td>
+ </tr>
+ <tr>
+ <td>relational</td>
+ <td><code>&lt; &lt;= &gt; &gt;= in instanceof</code></td>
+ </tr>
+ <tr>
+ <td>equality</td>
+ <td><code>== != === !==</code></td>
+ </tr>
+ <tr>
+ <td>bitwise-and</td>
+ <td><code>&amp;</code></td>
+ </tr>
+ <tr>
+ <td>bitwise-xor</td>
+ <td><code>^</code></td>
+ </tr>
+ <tr>
+ <td>bitwise-or</td>
+ <td><code>|</code></td>
+ </tr>
+ <tr>
+ <td>logical-and</td>
+ <td><code>&amp;&amp;</code></td>
+ </tr>
+ <tr>
+ <td>logical-or</td>
+ <td><code>||</code></td>
+ </tr>
+ <tr>
+ <td>conditional</td>
+ <td><code>?:</code></td>
+ </tr>
+ <tr>
+ <td>assignment</td>
+ <td><code>= += -= *= /= %= &lt;&lt;= &gt;&gt;= &gt;&gt;&gt;= &amp;= ^= |=</code></td>
+ </tr>
+ <tr>
+ <td>comma</td>
+ <td><code>,</code></td>
+ </tr>
+ </tbody>
+</table>
+
+<p>上表有一个更详细的版本,它包含了各操作符更详细的说明,可在 <a href="/zh-CN/docs/JavaScript/Reference/Operators/Operator_Precedence#Table" title="zh-CN/docs/JavaScript/Reference/Operators/Operator_Precedence#Table">JavaScript 参考手册</a> 中找到。</p>
+
+<h2 id="表达式">表达式</h2>
+
+<p>表达式是一组代码的集合,它返回一个值。(译注:定义比较不好理解,看下面的举例就很好懂了。)</p>
+
+<p>每一个合法的表达式都能计算成某个值,但从概念上讲,有两种类型的表达式:有副作用的(比如赋值)和单纯计算求值的。</p>
+
+<p>表达式x=7是第一类型的一个例子。该表达式使用=运算符将值7赋予变量x。这个表达式自己的值等于7。</p>
+
+<p>代码3 + 4是第二个表达式类型的一个例子。该表达式使用+运算符把3和4加到一起但并没有把结果(7)赋值给一个变量。</p>
+
+<p>JavaScript有以下表达式类型:</p>
+
+<ul>
+ <li>算数: 得出一个数字, 例如 3.14159. (通常使用 {{ web.link("#Arithmetic_operators", "arithmetic operators") }}.)</li>
+ <li>字符串: 得出一个字符串, 例如, "Fred" 或 "234". (通常使用 {{ web.link("#String_operators", "string operators") }}.)</li>
+ <li>逻辑值: 得出true或者false. (经常涉及到 {{ web.link("#Logical_operators", "logical operators") }}.)</li>
+ <li>基本表达式: javascript中基本的关键字和一般表达式。</li>
+ <li>左值表达式: 分配给左值。</li>
+</ul>
+
+<h3 id="new" name="new">基本表达式</h3>
+
+<h4 id="this" name="this"><code>this</code></h4>
+
+<p><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this"><code>this</code></a>关键字被用于指代当前的对象,通常,<code>this</code>指代的是方法中正在被调用的对象。用法如下:</p>
+
+<pre class="brush: js notranslate">this["propertyName"]
+this.propertyName
+</pre>
+
+<p>假设一个用于验证对象<code>value</code>属性的<code>validate</code>函数,传参有对象,最高值和最低值。</p>
+
+<pre class="brush: js notranslate">function validate(obj, lowval, hival){
+  if ((obj.value &lt; lowval) || (obj.value &gt; hival))
+    console.log("Invalid Value!");
+}
+</pre>
+
+<p>你可以在任何表单元素的<code>onchange</code>事件处理中调用<code>validat</code>函数,用<code>this</code>来指代当前的表单元素,用例如下:</p>
+
+<pre class="brush: html notranslate">&lt;p&gt;Enter a number between 18 and 99:&lt;/p&gt;
+&lt;input type="text" name="age" size=3 onChange="validate(this, 18, 99);"&gt;
+</pre>
+
+<h4 id="分组操作符">分组操作符</h4>
+
+<p>分组操作符()控制了表达式中计算的优先级. 举例来说, 你可以改变先乘除后加减的顺序,转而先计算加法。</p>
+
+<pre class="brush:js line-numbers language-js notranslate"><code class="language-js"><span class="keyword token">var</span> a <span class="operator token">=</span> <span class="number token">1</span><span class="punctuation token">;</span>
+<span class="keyword token">var</span> b <span class="operator token">=</span> <span class="number token">2</span><span class="punctuation token">;</span>
+<span class="keyword token">var</span> c <span class="operator token">=</span> <span class="number token">3</span><span class="punctuation token">;</span>
+
+<span class="comment token">// 默认优先级</span>
+a <span class="operator token">+</span> b <span class="operator token">*</span> c <span class="comment token">// 7</span>
+<span class="comment token">// 默认是这样计算的</span>
+a <span class="operator token">+</span> <span class="punctuation token">(</span>b <span class="operator token">*</span> c<span class="punctuation token">)</span> <span class="comment token">// 7</span>
+
+<span class="comment token">// 现在使加法优先于乘法</span>
+<span class="punctuation token">(</span>a <span class="operator token">+</span> b<span class="punctuation token">)</span> <span class="operator token">*</span> c <span class="comment token">// 9</span>
+
+<span class="comment token">// 这等价于</span>
+a <span class="operator token">*</span> c <span class="operator token">+</span> b <span class="operator token">*</span> c <span class="comment token">// 9</span></code></pre>
+
+<h5 id="数值推导">数值推导</h5>
+
+<p>Comprehensions 是一个带有实验性质的JavaScript特性, 计划将在未来的ECMAScript版本中加入该特性. 有两种类型的comprehensions:</p>
+
+<dl>
+ <dt>{{experimental_inline}} {{jsxref("Operators/Array_comprehensions", "[for (x of y) x]")}}</dt>
+ <dd>数列数值推导 (非标准用法)</dd>
+ <dt>{{experimental_inline}} {{jsxref("Operators/Generator_comprehensions", "(for (x of y) y)")}}</dt>
+ <dd>生成器数值推导 (译者注:生成器数值推导标准化可能不大,推荐使用 <a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/Generator_comprehensions">生成器函数</a>)</dd>
+</dl>
+
+<p>Comprehensions特性被许多编程语言所采用,该特性能够使你快速地通过一个已有的数组来创建出一个新的数组,比如:</p>
+
+<pre class="brush:js line-numbers language-js notranslate"><code class="language-js"><span class="punctuation token">[</span><span class="keyword token">for</span> <span class="punctuation token">(</span>i <span class="keyword token">of</span> <span class="punctuation token">[</span> <span class="number token">1</span><span class="punctuation token">,</span> <span class="number token">2</span><span class="punctuation token">,</span> <span class="number token">3</span> <span class="punctuation token">]</span><span class="punctuation token">)</span> i<span class="operator token">*</span>i <span class="punctuation token">]</span><span class="punctuation token">;</span>
+<span class="comment token">// [ 1, 4, 9 ]</span>
+
+<span class="keyword token">var</span> abc <span class="operator token">=</span> <span class="punctuation token">[</span> <span class="string token">"A"</span><span class="punctuation token">,</span> <span class="string token">"B"</span><span class="punctuation token">,</span> <span class="string token">"C"</span> <span class="punctuation token">]</span><span class="punctuation token">;</span>
+<span class="punctuation token">[</span><span class="keyword token">for</span> <span class="punctuation token">(</span>letters <span class="keyword token">of</span> abc<span class="punctuation token">)</span> letters<span class="punctuation token">.</span><span class="function token">toLowerCase</span><span class="punctuation token">(</span><span class="punctuation token">)</span><span class="punctuation token">]</span><span class="punctuation token">;</span>
+<span class="comment token">// [ "a", "b", "c" ]</span></code></pre>
+
+<h3 id="左值表达式">左值表达式</h3>
+
+<p>左值可以作为赋值的目标。</p>
+
+<h4 id="new" name="new"><code>new</code></h4>
+
+<p>你可以使用<a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/new"><code>new</code> operator</a> 创建一个自定义类型或者是<code>预置类型</code>的对象实例。用法如下:</p>
+
+<pre class="brush: js notranslate">var objectName = new objectType([param1, param2, ..., paramN]);
+</pre>
+
+<p>super</p>
+
+<p><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/super">super </a>关键字可以用来调用一个对象父类的函数,它在用来调用一个<a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes">类</a>的父类的构造函数时非常有用,比如:</p>
+
+<pre class="notranslate">super([arguments]); // calls the parent constructor. super.functionOnParent([arguments]);</pre>
+
+<h4 id="扩展语句">扩展语句</h4>
+
+<p><a href="/zh-CN/docs/Web/JavaScript/Reference/Operators/Spread_operator">扩展语句</a>符允许一个表达式在原地展开, 当需要多个参数 (比如函数调用时) 或者多个值(比如字面量数组) 。</p>
+
+<p><strong>例如:</strong>现在你有一个数组,你想创建一个新数组,并将刚才那个作为它的一部分,用array的字面语法是不够的,你不得不写一些代码实现它,比如用些<code>push</code>, <code>splice</code>, <code>concat等等。但是用</code>spread syntax就没问题了:</p>
+
+<pre class="notranslate"><code>var parts = ['shoulder', 'knees'];
+var lyrics = ['head', ...parts, 'and', 'toes'];</code></pre>
+
+<p>类似的,扩展语句也可以用在函数调用的时候:</p>
+
+<pre class="notranslate"><code>function f(x, y, z) { }
+var args = [0, 1, 2];
+f(...args);</code></pre>
+
+<div>{{PreviousNext("Web/JavaScript/Guide/Functions", "Web/JavaScript/Guide/Numbers_and_dates")}}</div>
diff --git a/files/zh-cn/web/javascript/guide/functions/index.html b/files/zh-cn/web/javascript/guide/functions/index.html
new file mode 100644
index 0000000000..bf26ec3c8e
--- /dev/null
+++ b/files/zh-cn/web/javascript/guide/functions/index.html
@@ -0,0 +1,662 @@
+---
+title: 函数
+slug: Web/JavaScript/Guide/Functions
+tags:
+ - JavaScript
+ - 函数
+ - 初学者
+ - 教程
+translation_of: Web/JavaScript/Guide/Functions
+---
+<p>{{jsSidebar("JavaScript Guide")}} {{PreviousNext("Web/JavaScript/Guide/Loops_and_iteration", "Web/JavaScript/Guide/Expressions_and_Operators")}}</p>
+
+<p class="summary">函数是 JavaScript 中的基本组件之一。 一个函数是 JavaScript 过程 — 一组执行任务或计算值的语句。要使用一个函数,你必须将其定义在你希望调用它的作用域内。</p>
+
+<p class="summary">一个JavaScript 函数用<code>function</code>关键字定义,后面跟着函数名和圆括号。</p>
+
+<p>查看 <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions">JavaScript 函数详细参考文档</a> 了解更多。</p>
+
+<h2 id="定义函数">定义函数</h2>
+
+<h3 id="函数声明">函数声明</h3>
+
+<p>一个<strong>函数定义</strong>(也称为<strong>函数声明</strong>,或<strong>函数语句</strong>)由一系列的<a href="/zh-CN/docs/JavaScript/Reference/Statements/function" title="function"><code>function</code></a>关键字组成,依次为:</p>
+
+<ul>
+ <li>函数的名称。</li>
+ <li>函数参数列表,包围在括号中并由逗号分隔。</li>
+ <li>定义函数的 JavaScript 语句,用大括号<code>{}</code>括起来。</li>
+</ul>
+
+<p>例如,以下的代码定义了一个简单的<code>square</code>函数:</p>
+
+<pre class="brush: js notranslate">function square(number) {
+ return number * number;
+}
+</pre>
+
+<p>函数<code>square</code>使用了一个参数,叫作<code>number</code>。这个函数只有一个语句,它说明该函数将函数的参数(即<code>number</code>)自乘后返回。函数的<a href="/en-US/docs/JavaScript/Reference/Statements/return" title="return"><code>return</code></a>语句确定了函数的返回值:</p>
+
+<pre class="brush: js notranslate">return number * number;
+</pre>
+
+<p>原始参数(比如一个具体的数字)被作为<strong>值</strong>传递给函数;值被传递给函数,如果被调用函数改变了这个参数的值,这样的改变不会影响到全局或调用函数。</p>
+
+<p>如果你传递一个对象(即一个非原始值,例如{{jsxref("Array")}}或用户自定义的对象)作为参数,而函数改变了这个对象的属性,这样的改变对函数外部是可见的,如下面的例子所示:</p>
+
+<pre class="brush: js notranslate">function myFunc(theObject) {
+ theObject.make = "Toyota";
+}
+
+var mycar = {make: "Honda", model: "Accord", year: 1998};
+var x, y;
+
+x = mycar.make; // x获取的值为 "Honda"
+
+myFunc(mycar);
+y = mycar.make; // y获取的值为 "Toyota"
+ // (make属性被函数改变了)
+</pre>
+
+<h3 id="函数表达式">函数表达式</h3>
+
+<p>虽然上面的函数声明在语法上是一个语句,但函数也可以由函数表达式创建。这样的函数可以是<strong>匿名</strong>的;它不必有一个名称。例如,函数<code>square</code>也可这样来定义:</p>
+
+<pre class="brush: js notranslate"><code>const square = function(number) { return number * number; };
+var x = square(4); // x gets the value 16</code></pre>
+
+<p>然而,函数表达式也可以提供函数名,并且可以用于在函数内部代指其本身,或者在调试器堆栈跟踪中识别该函数:</p>
+
+<pre class="brush: js notranslate">const factorial = function fac(n) {return n&lt;2 ? 1 : n*fac(n-1)};
+
+console.log(factorial(3));
+</pre>
+
+<p>当将函数作为参数传递给另一个函数时,函数表达式很方便。下面的例子演示了一个叫<code>map</code>的函数如何被定义,而后使用一个表达式函数作为其第一个参数进行调用:</p>
+
+<pre class="brush: js notranslate">function map(f,a) {
+ let result = []; // 创建一个数组
+  let i; // 声明一个值,用来循环
+ for (i = 0; i != a.length; i++)
+ result[i] = f(a[i]);
+ return result;
+}
+</pre>
+
+<p>下面的代码:</p>
+
+<pre class="brush: js line-numbers language-js notranslate"><code class="language-js">function map(f, a) {
+ let result = []; // 创建一个数组
+ let i; // 声明一个值,用来循环
+ for (i = 0; i != a.length; i++)
+ result[i] = f(a[i]);
+ return result;
+}
+const f = function(x) {
+ return x * x * x;
+}
+let numbers = [0,1, 2, 5,10];
+let cube = map(f,numbers);
+console.log(cube);</code></pre>
+
+<p>返回 [0, 1, 8, 125, 1000]。</p>
+
+<p>在 JavaScript 中,可以根据条件来定义一个函数。比如下面的代码,当<code>num</code> 等于 0 的时候才会定义 <code>myFunc</code> :</p>
+
+<pre class="brush: js notranslate">var myFunc;
+if (num == 0){
+ myFunc = function(theObject) {
+ theObject.make = "Toyota"
+ }
+}</pre>
+
+<p>除了上述的定义函数方法外,你也可以在运行时用 {{jsxref("Function")}} 构造器由一个字符串来创建一个函数 ,很像 {{jsxref("Global_Objects/eval", "eval()")}} 函数。</p>
+
+<p>当一个函数是一个对象的属性时,称之为<strong>方法</strong>。了解更多关于对象和方法的知识 <a href="/zh-CN/docs/Web/JavaScript/Guide/Working_with_Objects" title="en-US/docs/JavaScript/Guide/Working with Objects">使用对象</a>。</p>
+
+<h2 id="调用函数">调用函数</h2>
+
+<p>定义一个函数并不会自动的执行它。定义了函数仅仅是赋予函数以名称并明确函数被调用时该做些什么。<strong>调用</strong>函数才会以给定的参数真正执行这些动作。例如,一旦你定义了函数<code>square</code>,你可以如下这样调用它:</p>
+
+<pre class="brush: js notranslate">square(5);
+</pre>
+
+<p>上述语句通过提供参数 5 来调用函数。函数执行完它的语句会返回值25。</p>
+
+<p>函数一定要处于调用它们的域中,但是函数的声明可以被提升(出现在调用语句之后),如下例:</p>
+
+<pre class="brush: js notranslate">console.log(square(5));
+/* ... */
+function square(n) { return n*n }
+</pre>
+
+<p>函数域是指函数声明时的所在的地方,或者函数在顶层被声明时指整个程序。</p>
+
+<div class="note">
+<p><strong>提示:</strong>注意只有使用如上的语法形式(即 <code>function funcName(){}</code>)才可以。而下面的代码是无效的。就是说,函数提升仅适用于函数声明,而不适用于函数表达式。</p>
+</div>
+
+<pre class="brush: js example-bad line-numbers language-js notranslate"><code class="language-js">console.log(square); // square is hoisted with an initial value undefined.
+console.log(square(5)); // Uncaught TypeError: square is not a function
+const square = function (n) {
+ return n * n;
+}</code></pre>
+
+<p>函数的参数并不局限于字符串或数字。你也可以将整个对象传递给函数。函数 <code>show_props</code>(其定义参见 <a href="https://developer.mozilla.org/en-US/docs/JavaScript/Guide/Working_with_Objects#Objects_and_Properties" title="https://developer.mozilla.org/en-US/docs/JavaScript/Guide/Working_with_Objects#Objects_and_Properties">用对象编程</a>)就是一个将对象作为参数的例子。</p>
+
+<p>函数可以被递归,就是说函数可以调用其本身。例如,下面这个函数就是用递归计算阶乘:</p>
+
+<pre class="brush: js notranslate">function factorial(n){
+ if ((n == 0) || (n == 1))
+ return 1;
+ else
+ return (n * factorial(n - 1));
+}
+</pre>
+
+<p>你可以计算1-5的阶乘如下:</p>
+
+<pre class="brush: js notranslate">var a, b, c, d, e;
+
+a = factorial(1); // 1赋值给a
+b = factorial(2); // 2赋值给b
+c = factorial(3); // 6赋值给c
+d = factorial(4); // 24赋值给d
+e = factorial(5); // 120赋值给e
+</pre>
+
+<p>还有其它的方式来调用函数。常见的一些情形是某些地方需要动态调用函数,或者函数的实参数量是变化的,或者调用函数的上下文需要指定为在运行时确定的特定对象。显然,函数本身就是对象,因此这些对象也有方法(参考{{jsxref("Function")}} )。作为此中情形之一,{{jsxref("Function.apply", "apply()")}}方法可以实现这些目的。</p>
+
+<h2 class="deki-transform" id="函数作用域">函数作用域</h2>
+
+<p>在函数内定义的变量不能在函数之外的任何地方访问,因为变量仅仅在该函数的域的内部有定义。相对应的,一个函数可以访问定义在其范围内的任何变量和函数。换言之,定义在全局域中的函数可以访问所有定义在全局域中的变量。在另一个函数中定义的函数也可以访问在其父函数中定义的所有变量和父函数有权访问的任何其他变量。</p>
+
+<pre class="brush: js notranslate">// 下面的变量定义在全局作用域(global scope)中
+var num1 = 20,
+ num2 = 3,
+ name = "Chamahk";
+
+// 本函数定义在全局作用域
+function multiply() {
+ return num1 * num2;
+}
+
+multiply(); // 返回 60
+
+// 嵌套函数的例子
+function getScore() {
+ var num1 = 2,
+ num2 = 3;
+
+ function add() {
+ return name + " scored " + (num1 + num2);
+ }
+
+ return add();
+}
+
+getScore(); // 返回 "Chamahk scored 5"
+</pre>
+
+<h2 id="作用域和函数堆栈">作用域和函数堆栈</h2>
+
+<h3 id="递归">递归</h3>
+
+<p>一个函数可以指向并调用自身。有三种方法可以达到这个目的:</p>
+
+<ol>
+ <li>函数名</li>
+ <li><code><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/arguments/callee">arguments.callee</a></code></li>
+ <li>作用域下的一个指向该函数的变量名</li>
+</ol>
+
+<p>例如,思考一下如下的函数定义:</p>
+
+<pre class="brush: js notranslate">var foo = function bar() {
+ // statements go here
+};
+</pre>
+
+<p>在这个函数体内,以下的语句是等价的:</p>
+
+<ol>
+ <li><code>bar()</code></li>
+ <li><code>arguments.callee()</code> <strong>(译者注:ES5禁止在严格模式下使用此属性)</strong></li>
+ <li><code>foo()</code></li>
+</ol>
+
+<p>调用自身的函数我们称之为<em>递归函数</em>。在某种意义上说,递归近似于循环。两者都重复执行相同的代码,并且两者都需要一个终止条件(避免无限循环或者无限递归)。例如以下的循环:</p>
+
+<pre class="brush: js notranslate">var x = 0;
+while (x &lt; 10) { // "x &lt; 10" 是循环条件
+ // do stuff
+ x++;
+}
+</pre>
+
+<p>可以被转化成一个递归函数和对其的调用:</p>
+
+<pre class="brush: js notranslate">function loop(x) {
+ if (x &gt;= 10) // "x &gt;= 10" 是退出条件(等同于 "!(x &lt; 10)")
+ return;
+ // 做些什么
+ loop(x + 1); // 递归调用
+}
+loop(0);
+</pre>
+
+<p>不过,有些算法并不能简单的用迭代来实现。例如,获取树结构中所有的节点时,使用递归实现要容易得多:</p>
+
+<pre class="brush: js notranslate">function walkTree(node) {
+ if (node == null) //
+ return;
+ // do something with node
+ for (var i = 0; i &lt; node.childNodes.length; i++) {
+ walkTree(node.childNodes[i]);
+ }
+}
+</pre>
+
+<p>跟<code>loop</code>函数相比,这里每个递归调用都产生了更多的递归。</p>
+
+<p>将递归算法转换为非递归算法是可能的,不过逻辑上通常会更加复杂,而且需要使用堆栈。事实上,递归函数就使用了堆栈:函数堆栈。</p>
+
+<p>这种类似堆栈的行为可以在下例中看到:</p>
+
+<pre class="brush: js notranslate">function foo(i) {
+ if (i &lt; 0)
+ return;
+ console.log('begin:' + i);
+ foo(i - 1);
+ console.log('end:' + i);
+}
+foo(3);
+
+// 输出:
+
+// begin:3
+// begin:2
+// begin:1
+// begin:0
+// end:0
+// end:1
+// end:2
+// end:3</pre>
+
+<h3 id="嵌套函数和闭包">嵌套函数和闭包</h3>
+
+<p>你可以在一个函数里面嵌套另外一个函数。嵌套(内部)函数对其容器(外部)函数是私有的。它自身也形成了一个闭包。一个闭包是一个可以自己拥有独立的环境与变量的表达式(通常是函数)。</p>
+
+<p>既然嵌套函数是一个闭包,就意味着一个嵌套函数可以”继承“容器函数的参数和变量。换句话说,内部函数包含外部函数的作用域。</p>
+
+<p>可以总结如下:</p>
+
+<ul>
+ <li>内部函数只可以在外部函数中访问。</li>
+ <li>内部函数形成了一个闭包:它可以访问外部函数的参数和变量,但是外部函数却不能使用它的参数和变量。</li>
+</ul>
+
+<p>下面的例子展示了嵌套函数:</p>
+
+<pre class="brush: js notranslate">function addSquares(a, b) {
+ function square(x) {
+ return x * x;
+ }
+ return square(a) + square(b);
+}
+a = addSquares(2, 3); // returns 13
+b = addSquares(3, 4); // returns 25
+c = addSquares(4, 5); // returns 41</pre>
+
+<p>由于内部函数形成了闭包,因此你可以调用外部函数并为外部函数和内部函数指定参数:</p>
+
+<pre class="brush: js notranslate">function outside(x) {
+ function inside(y) {
+ return x + y;
+ }
+ return inside;
+}
+fn_inside = outside(3); // 可以这样想:给一个函数,使它的值加3
+result = fn_inside(5); // returns 8
+
+result1 = outside(3)(5); // returns 8</pre>
+
+<h3 id="保存变量">保存变量</h3>
+
+<p>注意到上例中 <code>inside</code> 被返回时 <code>x</code> 是怎么被保留下来的。一个闭包必须保存它可见作用域中所有参数和变量。因为每一次调用传入的参数都可能不同,每一次对外部函数的调用实际上重新创建了一遍这个闭包。只有当返回的 <code>inside</code> 没有再被引用时,内存才会被释放。</p>
+
+<p>这与在其他对象中存储引用没什么不同,但是通常不太明显,因为并不能直接设置引用,也不能检查它们。</p>
+
+<h3 id="多层嵌套函数">多层嵌套函数</h3>
+
+<p>函数可以被多层嵌套。例如,函数A可以包含函数B,函数B可以再包含函数C。B和C都形成了闭包,所以B可以访问A,C可以访问B和A。因此,闭包可以包含多个作用域;他们递归式的包含了所有包含它的函数作用域。这个称之为作用<em>域链</em>。(稍后会详细解释)</p>
+
+<p>思考一下下面的例子:</p>
+
+<pre class="brush: js notranslate">function A(x) {
+ function B(y) {
+ function C(z) {
+ console.log(x + y + z);
+ }
+ C(3);
+ }
+ B(2);
+}
+A(1); // logs 6 (1 + 2 + 3)</pre>
+
+<p>在这个例子里面,C可以访问B的y和A的x。这是因为:</p>
+
+<ol>
+ <li>B形成了一个包含A的闭包,B可以访问A的参数和变量</li>
+ <li>C形成了一个包含B的闭包</li>
+ <li>B包含A,所以C也包含A,C可以访问B和A的参数和变量。换言之,C用这个顺序链接了B和A的作用域</li>
+</ol>
+
+<p>反过来却不是这样。A不能访问C,因为A看不到B中的参数和变量,C是B中的一个变量,所以C是B私有的。</p>
+
+<h3 id="命名冲突">命名冲突</h3>
+
+<p>当同一个闭包作用域下两个参数或者变量同名时,就会产生命名冲突。更近的作用域有更高的优先权,所以最近的优先级最高,最远的优先级最低。这就是作用域链。链的第一个元素就是最里面的作用域,最后一个元素便是最外层的作用域。</p>
+
+<p>看以下的例子:</p>
+
+<pre class="brush: js notranslate">function outside() {
+ var x = 5;
+ function inside(x) {
+ return x * 2;
+ }
+ return inside;
+}
+
+outside()(10); // returns 20 instead of 10</pre>
+
+<p>命名冲突发生在<code>return x</code>上,<code>inside</code>的参数<code>x</code>和<code>outside</code>变量<code>x</code>发生了冲突。这里的作用链域是{<code style="font-style: normal;">inside</code>, <code style="font-style: normal;">outside</code>, 全局对象}。因此<code>inside</code>的<code>x</code>具有最高优先权,返回了20(<code>inside</code>的<code>x</code>)而不是10(<code>outside</code>的<code>x</code>)。</p>
+
+<h2 id="闭包">闭包</h2>
+
+<p>闭包是 JavaScript 中最强大的特性之一。JavaScript 允许函数嵌套,并且内部函数可以访问定义在外部函数中的所有变量和函数,以及外部函数能访问的所有变量和函数。</p>
+
+<p>但是,外部函数却不能够访问定义在内部函数中的变量和函数。这给内部函数的变量提供了一定的安全性。</p>
+
+<p>此外,由于内部函数可以访问外部函数的作用域,因此当内部函数生存周期大于外部函数时,外部函数中定义的变量和函数的生存周期将比内部函数执行时间长。当内部函数以某一种方式被任何一个外部函数作用域访问时,一个闭包就产生了。</p>
+
+<pre class="brush: js notranslate">var pet = function(name) { //外部函数定义了一个变量"name"
+ var getName = function() {
+  //内部函数可以访问 外部函数定义的"name"
+ return name;
+ }
+  //返回这个内部函数,从而将其暴露在外部函数作用域
+ return getName;
+};
+myPet = pet("Vivie");
+
+myPet(); // 返回结果 "Vivie"
+</pre>
+
+<p>实际上可能会比上面的代码复杂的多。在下面这种情形中,返回了一个包含可以操作外部函数的内部变量方法的对象。</p>
+
+<pre class="brush: js notranslate">var createPet = function(name) {
+ var sex;
+
+ return {
+ setName: function(newName) {
+ name = newName;
+ },
+
+ getName: function() {
+ return name;
+ },
+
+ getSex: function() {
+ return sex;
+ },
+
+ setSex: function(newSex) {
+ if(typeof newSex == "string"
+  &amp;&amp; (newSex.toLowerCase() == "male" || newSex.toLowerCase() == "female")) {
+ sex = newSex;
+ }
+ }
+ }
+}
+
+var pet = createPet("Vivie");
+pet.getName(); // Vivie
+
+pet.setName("Oliver");
+pet.setSex("male");
+pet.getSex(); // male
+pet.getName(); // Oliver
+</pre>
+
+<p>在上面的代码中,外部函数的<code>name</code>变量对内嵌函数来说是可取得的,而除了通过内嵌函数本身,没有其它任何方法可以取得内嵌的变量。内嵌函数的内嵌变量就像内嵌函数的保险柜。它们会为内嵌函数保留“稳定”——而又安全——的数据参与运行。而这些内嵌函数甚至不会被分配给一个变量,或者不必一定要有名字。</p>
+
+<pre class="brush: js notranslate">var getCode = (function(){
+ var secureCode = "0]Eal(eh&amp;2"; // A code we do not want outsiders to be able to modify...
+
+ return function () {
+ return secureCode;
+ };
+})();
+
+getCode(); // Returns the secret code
+</pre>
+
+<div class="blockIndicator note">
+<p>尽管有上述优点,使用闭包时仍然要小心避免一些陷阱。如果一个闭包的函数定义了一个和外部函数的某个变量名称相同的变量,那么这个闭包将无法引用外部函数的这个变量。</p>
+
+<pre class="brush: js notranslate">var createPet = function(name) { // Outer function defines a variable called "name"
+ return {
+ setName: function(name) { // Enclosed function also defines a variable called "name"
+ name = name; // ??? How do we access the "name" defined by the outer function ???
+ }
+ }
+}
+</pre>
+</div>
+
+<h2 id="使用_arguments_对象">使用 arguments 对象</h2>
+
+<p>函数的实际参数会被保存在一个类似数组的arguments对象中。在函数内,你可以按如下方式找出传入的参数:</p>
+
+<pre class="brush: js notranslate">arguments[i]
+</pre>
+
+<p>其中<code>i</code>是参数的序数编号(译注:数组索引),以0开始。所以第一个传来的参数会是<code>arguments[0]</code>。参数的数量由<code>arguments.length</code>表示。</p>
+
+<p>使用arguments对象,你可以处理比声明的更多的参数来调用函数。这在你事先不知道会需要将多少参数传递给函数时十分有用。你可以用<code>arguments.length</code>来获得实际传递给函数的参数的数量,然后用<code>arguments</code>对象来取得每个参数。</p>
+
+<p>例如,设想有一个用来连接字符串的函数。唯一事先确定的参数是在连接后的字符串中用来分隔各个连接部分的字符(译注:比如例子里的分号“;”)。该函数定义如下:</p>
+
+<pre class="brush: js line-numbers language-js notranslate"><code class="language-js"><span class="keyword token">function</span> <span class="function token">myConcat</span><span class="punctuation token">(</span>separator<span class="punctuation token">)</span> <span class="punctuation token">{</span>
+ <span class="keyword token">var</span> result <span class="operator token">=</span> <span class="string token">''</span><span class="punctuation token">;</span> <span class="comment token">// 把值初始化成一个字符串,这样就可以用来保存字符串了!!</span>
+ <span class="keyword token">var</span> i<span class="punctuation token">;</span>
+ <span class="comment token">// iterate through arguments</span>
+ <span class="keyword token">for</span> <span class="punctuation token">(</span>i <span class="operator token">=</span> <span class="number token">1</span><span class="punctuation token">;</span> i <span class="operator token">&lt;</span> arguments<span class="punctuation token">.</span>length<span class="punctuation token">;</span> i<span class="operator token">++</span><span class="punctuation token">)</span> <span class="punctuation token">{</span>
+ result <span class="operator token">+</span><span class="operator token">=</span> arguments<span class="punctuation token">[</span>i<span class="punctuation token">]</span> <span class="operator token">+</span> separator<span class="punctuation token">;</span>
+ <span class="punctuation token">}</span>
+ <span class="keyword token">return</span> result<span class="punctuation token">;</span>
+<span class="punctuation token">}</span></code></pre>
+
+<p>你可以给这个函数传递任意数量的参数,它会将各个参数连接成一个字符串“列表”:</p>
+
+<pre class="brush: js notranslate">// returns "red, orange, blue, "
+myConcat(", ", "red", "orange", "blue");
+
+// returns "elephant; giraffe; lion; cheetah; "
+myConcat("; ", "elephant", "giraffe", "lion", "cheetah");
+
+// returns "sage. basil. oregano. pepper. parsley. "
+myConcat(". ", "sage", "basil", "oregano", "pepper", "parsley");
+</pre>
+
+<div class="note"><strong>提示:</strong><code>arguments</code>变量只是 <em>”</em><strong>类数组对象</strong>“,并不是一个数组。称其为类数组对象是说它有一个索引编号和<code>length</code>属性。尽管如此,它并不拥有全部的Array对象的操作方法。</div>
+
+<p>更多信息请阅读JavaScript参考里的{{jsxref("Function")}}一文。</p>
+
+<h2 id="函数参数">函数参数</h2>
+
+<p>从ECMAScript 6开始,有两个新的类型的参数:默认参数,剩余参数。</p>
+
+<h3 id="默认参数">默认参数</h3>
+
+<p>在JavaScript中,函数参数的默认值是<code>undefined</code>。然而,在某些情况下设置不同的默认值是有用的。这时默认参数可以提供帮助。</p>
+
+<p>在过去,用于设定默认参数的一般策略是在函数的主体中测试参数值是否为<code>undefined</code>,如果是则赋予这个参数一个默认值。如果在下面的例子中,调用函数时没有实参传递给<code>b</code>,那么它的值就是<code>undefined</code>,于是计算<code>a*b</code>得到、函数返回的是 <code>NaN</code>。但是,在下面的例子中,这个已经被第二行获取处理:</p>
+
+<pre class="brush: js notranslate">function multiply(a, b) {
+ b = (typeof b !== 'undefined') ? b : 1;
+
+ return a*b;
+}
+
+multiply(5); // 5
+</pre>
+
+<p>使用默认参数,在函数体的检查就不再需要了。现在,你可以在函数头简单地把1设定为<code>b</code>的默认值:</p>
+
+<pre class="brush: js notranslate">function multiply(a, b = 1) {
+ return a*b;
+}
+
+multiply(5); // 5</pre>
+
+<p>了解更多<a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Default_parameters">默认参数</a>的信息。</p>
+
+<h3 id="剩余参数">剩余参数</h3>
+
+<p><a href="/zh-CN/docs/Web/JavaScript/Reference/Functions/rest_parameters">剩余参数</a>语法允许将不确定数量的参数表示为数组。在下面的例子中,使用剩余参数收集从第二个到最后参数。然后,我们将这个数组的每一个数与第一个参数相乘。这个例子是使用了一个箭头函数,这将在下一节介绍。</p>
+
+<pre class="brush: js notranslate">function multiply(multiplier, ...theArgs) {
+ return theArgs.map(x =&gt; multiplier * x);
+}
+
+var arr = multiply(2, 1, 2, 3);
+console.log(arr); // [2, 4, 6]</pre>
+
+<h2 id="箭头函数">箭头函数</h2>
+
+<p><a href="/zh-CN/docs/Web/JavaScript/Reference/Functions/Arrow_functions">箭头函数表达式</a>(也称胖箭头函数)相比函数表达式具有较短的语法并以词法的方式绑定 <code>this</code>。箭头函数总是匿名的。另见 hacks.mozilla.org 的博文:“<a href="https://hacks.mozilla.org/2015/06/es6-in-depth-arrow-functions/">深度了解ES6:箭头函数</a>”。</p>
+
+<p>有两个因素会影响引入箭头函数:更简洁的函数和 <code>this</code>。</p>
+
+<h3 id="更简洁的函数">更简洁的函数</h3>
+
+<p>在一些函数模式中,更简洁的函数很受欢迎。对比一下:</p>
+
+<pre class="brush: js line-numbers language-js notranslate"><code class="language-js">var a = [
+ "Hydrogen",
+ "Helium",
+ "Lithium",
+ "Beryllium"
+];
+
+var a2 = a.map(function(s){ return s.length });
+
+console.log(a2); // logs [ 8, 6, 7, 9 ]
+
+var a3 = a.map( s =&gt; s.length );
+
+console.log(a3); // logs [ 8, 6, 7, 9 ]</code></pre>
+
+<h3 id="this_的词法"><code>this</code> 的词法</h3>
+
+<p>在箭头函数出现之前,每一个新函数都重新定义了自己的 <a href="/zh-CN/docs/Web/JavaScript/Reference/Operators/this">this</a> 值(在构造函数中是一个新的对象;在严格模式下是未定义的;在作为“对象方法”调用的函数中指向这个对象;等等)。以面向对象的编程风格,这样着实有点恼人。</p>
+
+<pre class="brush: js line-numbers language-js notranslate"><code class="language-js">function Person() {
+ // 构造函数Person()将`this`定义为自身
+ this.age = 0;
+
+ setInterval(function growUp() {
+ // 在非严格模式下,growUp()函数将`this`定义为“全局对象”,
+ // 这与Person()定义的`this`不同,
+  // 所以下面的语句不会起到预期的效果。
+ this.age++;
+ }, 1000);
+}
+
+var p = new Person();</code></pre>
+
+<p>在ECMAScript 3/5里,通过把<code>this</code>的值赋值给一个变量可以修复这个问题。</p>
+
+<pre class="brush: js line-numbers language-js notranslate"><code class="language-js">function Person() {
+ var self = this; // 有的人习惯用`that`而不是`self`,
+  // 无论你选择哪一种方式,请保持前后代码的一致性
+ self.age = 0;
+
+ setInterval(function growUp() {
+ // 以下语句可以实现预期的功能
+ self.age++;
+ }, 1000);
+}</code></pre>
+
+<p>另外,创建一个<a href="/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Function/bind">约束函数</a>可以使得 <code>this</code>值被正确传递给 <code>growUp()</code> 函数。</p>
+
+<p>箭头函数捕捉闭包上下文的<code>this</code>值,所以下面的代码工作正常。</p>
+
+<pre class="brush: js line-numbers language-js notranslate"><code class="language-js">function Person(){
+ this.age = 0;
+
+ setInterval(() =&gt; {
+ this.age++; // 这里的`this`正确地指向person对象
+ }, 1000);
+}
+
+var p = new Person();</code></pre>
+
+<h2 id="预定义函数">预定义函数</h2>
+
+<p>JavaScript语言有好些个顶级的内建函数:</p>
+
+<dl>
+ <dt>{{jsxref("Global_Objects/eval", "eval()")}}</dt>
+ <dd>
+ <p><code><strong>eval()</strong></code>方法会对一串字符串形式的JavaScript代码字符求值。</p>
+ </dd>
+ <dt>{{jsxref("Global_Objects/uneval", "uneval()")}} {{non-standard_inline}}</dt>
+ <dd>
+ <p><code><strong>uneval()</strong></code>方法创建的一个{{jsxref("Object")}}的源代码的字符串表示。</p>
+ </dd>
+ <dt>{{jsxref("Global_Objects/isFinite", "isFinite()")}}</dt>
+ <dd>
+ <p><code><strong>isFinite()</strong></code>函数判断传入的值是否是有限的数值。 如果需要的话,其参数首先被转换为一个数值。</p>
+ </dd>
+ <dt>{{jsxref("Global_Objects/isNaN", "isNaN()")}}</dt>
+ <dd>
+ <p><code><strong>isNaN()</strong></code>函数判断一个值是否是{{jsxref("Global_Objects/NaN", "NaN")}}。注意:<code>isNaN</code>函数内部的<code><a href="/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/isNaN#Description">强制转换规则</a></code>十分有趣; 另一个可供选择的是ECMAScript 6 中定义{{jsxref("Number.isNaN()")}} , 或者使用 <code><a href="/zh-CN/docs/Web/JavaScript/Reference/Operators/typeof">typeof</a></code>来判断数值类型。</p>
+ </dd>
+ <dt>{{jsxref("Global_Objects/parseFloat", "parseFloat()")}}</dt>
+ <dd>
+ <p><code><strong>parseFloat()</strong></code> 函数解析字符串参数,并返回一个浮点数。</p>
+ </dd>
+ <dt>{{jsxref("Global_Objects/parseInt", "parseInt()")}}</dt>
+ <dd>
+ <p><code><strong>parseInt()</strong></code> 函数解析字符串参数,并返回指定的基数(基础数学中的数制)的整数。</p>
+ </dd>
+ <dt>{{jsxref("Global_Objects/decodeURI", "decodeURI()")}}</dt>
+ <dd>
+ <p><code><strong>decodeURI()</strong></code> 函数对先前经过{{jsxref("Global_Objects/encodeURI", "encodeURI")}}函数或者其他类似方法编码过的字符串进行解码。</p>
+ </dd>
+ <dt>{{jsxref("Global_Objects/decodeURIComponent", "decodeURIComponent()")}}</dt>
+ <dd>
+ <p><code><strong>decodeURIComponent()</strong></code>方法对先前经过{{jsxref("Global_Objects/encodeURIComponent", "encodeURIComponent")}}函数或者其他类似方法编码过的字符串进行解码。</p>
+ </dd>
+ <dt>{{jsxref("Global_Objects/encodeURI", "encodeURI()")}}</dt>
+ <dd>
+ <p><code><strong>encodeURI()</strong></code>方法通过用以一个,两个,三个或四个转义序列表示字符的UTF-8编码替换统一资源标识符(URI)的某些字符来进行编码(每个字符对应四个转义序列,这四个序列组了两个”替代“字符)。</p>
+ </dd>
+ <dt>{{jsxref("Global_Objects/encodeURIComponent", "encodeURIComponent()")}}</dt>
+ <dd>
+ <p><code><strong>encodeURIComponent()</strong></code> 方法通过用以一个,两个,三个或四个转义序列表示字符的UTF-8编码替换统一资源标识符(URI)的每个字符来进行编码(每个字符对应四个转义序列,这四个序列组了两个”替代“字符)。</p>
+ </dd>
+ <dt>{{jsxref("Global_Objects/escape", "escape()")}} {{deprecated_inline}}</dt>
+ <dd>
+ <p>已废弃的 <code><strong>escape()</strong></code> 方法计算生成一个新的字符串,其中的某些字符已被替换为十六进制转义序列。使用 {{jsxref("Global_Objects/encodeURI", "encodeURI")}}或者{{jsxref("Global_Objects/encodeURIComponent", "encodeURIComponent")}}替代本方法。</p>
+ </dd>
+ <dt>{{jsxref("Global_Objects/unescape", "unescape()")}} {{deprecated_inline}}</dt>
+ <dd>
+ <p>已废弃的 <code><strong>unescape()</strong></code> 方法计算生成一个新的字符串,其中的十六进制转义序列将被其表示的字符替换。上述的转义序列就像{{jsxref("Global_Objects/escape", "escape")}}里介绍的一样。因为 <code>unescape</code> 已经废弃,建议使用{{jsxref("Global_Objects/decodeURI", "decodeURI()")}}或者{{jsxref("Global_Objects/decodeURIComponent", "decodeURIComponent")}} 替代本方法。</p>
+ </dd>
+</dl>
+
+<div>{{PreviousNext("Web/JavaScript/Guide/Loops_and_iteration", "Web/JavaScript/Guide/Expressions_and_Operators")}}</div>
diff --git a/files/zh-cn/web/javascript/guide/grammar_and_types/index.html b/files/zh-cn/web/javascript/guide/grammar_and_types/index.html
new file mode 100644
index 0000000000..0ea7538a96
--- /dev/null
+++ b/files/zh-cn/web/javascript/guide/grammar_and_types/index.html
@@ -0,0 +1,705 @@
+---
+title: 语法和数据类型
+slug: Web/JavaScript/Guide/Grammar_and_types
+tags:
+ - Enhanced Object Literals
+ - JavaScript
+ - 'Null'
+ - Object Literals
+ - Typed Objects
+ - typeof()
+ - 教程
+translation_of: Web/JavaScript/Guide/Grammar_and_types
+---
+<p>{{jsSidebar("JavaScript Guide")}} {{PreviousNext("Web/JavaScript/Guide/Introduction", "Web/JavaScript/Guide/Control_flow_and_error_handling")}}</p>
+
+<p class="summary">本章讨论 JavaScript 的基本语法,变量声明,数据类型 和 字面量。</p>
+
+<h2 id="基础">基础</h2>
+
+<p>JavaScript 借鉴了 Java 的大部分语法,但同时也受到 <em>Awk,Perl </em>和 <em>Python</em>的影响。 </p>
+
+<p>JavaScript 是<strong>区分大小写</strong>的,并使用 <strong>Unicode </strong>字符集。举个例子,可以将单词 Früh (在德语中意思是“早”)用作变量名。</p>
+
+<pre class="notranslate"><code>var Früh = "foobar";</code></pre>
+
+<p>但是,由于 JavaScript 是大小写敏感的,因此变量 <code>früh</code> 和 <code>Früh</code> 则是两个不同的变量。</p>
+
+<p>在 JavaScript 中,指令被称为语句 ({{Glossary("Statement")}}),并用分号(;)进行分隔。</p>
+
+<p>如果一条语句独占一行的话,那么分号是可以省略的。(译者注:并不建议这么做。)但如果一行中有多条语句,那么这些语句必须以分号分开。 ECMAScript 规定了在语句的末尾自动插入分号(<a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Lexical_grammar#Automatic_semicolon_insertion">ASI</a>)。(如果想要了解更多信息,请参阅 JavaScript <a href="/zh-CN/docs/Web/JavaScript/Reference/Lexical_grammar">词法语法</a> 。)虽然不是必需的,但是在一条语句的末尾加上分号是一个很好的习惯。这个习惯可以大大减少代码中产生 bug 的可能性。</p>
+
+<p> Javascript 源码从左往右被扫描并转换成一系列由 token 、控制字符、行终止符、注释和空白字符组成的输入元素。空白字符指的是空格、制表符和换行符等。</p>
+
+<h2 id="注释">注释</h2>
+
+<p><strong>Javascript 注释</strong>的语法和 C++ 或许多其他语言类似:</p>
+
+<pre class="brush: js notranslate">// 单行注释
+
+/* 这是一个更长的,
+ 多行注释
+*/
+
+/* 然而, 你不能, /* 嵌套注释 */ <strong>语法错误</strong> */</pre>
+
+<p>在代码执行过程中,注释将被自动跳过(不执行)。</p>
+
+<h2 id="声明">声明</h2>
+
+<p>JavaScript有三种声明方式。</p>
+
+<dl>
+ <dt>{{jsxref("Statements/var", "var")}}</dt>
+ <dd>声明一个变量,可选初始化一个值。</dd>
+ <dt>{{jsxref("Statements/let", "let")}}</dt>
+ <dd>声明一个块作用域的局部变量,可选初始化一个值。</dd>
+ <dt>{{jsxref("Statements/const", "const")}}</dt>
+ <dd>声明一个块作用域的只读常量。</dd>
+</dl>
+
+<h3 id="变量">变量</h3>
+
+<p>在应用程序中,使用变量来作为值的符号名。变量的名字又叫做{{Glossary("Identifier", "标识符")}},其需要遵守一定的规则。</p>
+
+<p>一个 JavaScript 标识符必须以字母、下划线(_)或者美元符号($)开头;后续的字符也可以是数字(0-9)。因为 JavaScript 语言是区分大小写的,所以字母可以是从“A”到“Z”的大写字母和从“a”到“z”的小写字母。</p>
+
+<p>你可以使用大部分 ISO 8859-1 或 Unicode 编码的字符作标识符,例如 å 和 ü(详情可查看<a href="https://mathiasbynens.be/notes/javascript-identifiers-es6">这篇博客文章</a>)。你也可以使用 <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Lexical_grammar#String_literals">Unicode 转义字符</a> 作标识符。</p>
+
+<p>合法的标识符示例:<code>Number_hits</code>,<code>temp99</code>,<code>$credit</code> 和 <code>_name</code>。</p>
+
+<h3 id="声明变量">声明变量</h3>
+
+<p>你可以用以下三种方式声明变量:</p>
+
+<ul>
+ <li>使用关键词 <code>var</code> 。例如 <code>var x = 42</code>。这个语法可以用来声明局部变量和全局变量。</li>
+ <li>直接赋值。例如<code>x = 42</code>。在函数外使用这种形式赋值,会产生一个全局变量。在严格模式下会产生错误。因此你不应该使用这种方式来声明变量。</li>
+ <li>使用关键词 <code>let</code> 。例如 <code>let y = 13</code>。这个语法可以用来声明块作用域的局部变量。參考下方<a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Guide/Grammar_and_types#变量的作用域">变量的作用域(Variable scope)</a> 。</li>
+</ul>
+
+<h3 id="变量求值">变量求值</h3>
+
+<p>用 <code>var</code> 或 <code>let</code> 语句声明的变量,如果没有赋初始值,则其值为 <code>undefined</code> 。</p>
+
+<p>如果访问一个未声明的变量会导致抛出一个引用错误(ReferenceError)异常:</p>
+
+<pre class="brush: js notranslate">var a;
+console.log("The value of a is " + a); // a 的值是 undefined
+
+console.log("The value of b is " + b);// b 的值是 undefined
+var b;
+// 在你阅读下面的‘变量声明提升’前你可能会疑惑
+
+console.log("The value of c is " + c); // 未捕获的引用错误: c 未被定义
+
+let x;
+console.log("The value of x is " + x); // x 的值是 undefined
+
+console.log("The value of y is " + y);// 未捕获的引用错误: y 未被定义
+let y;</pre>
+
+<p>你可以使用 <code>undefined</code> 来判断一个变量是否已赋值。在以下的代码中,变量<code>input</code>未被赋值,因此 <code><a href="https://developer.mozilla.org/zh-CN/docs/JavaScript/Reference/Statements/if...else" title="zh-CN/docs/JavaScript/Reference/Statements/if...else">if</a></code> 条件语句的求值结果是 <code>true</code> 。</p>
+
+<pre class="brush: js notranslate">var input;
+if(input === undefined){
+ doThis();
+} else {
+ doThat();
+}
+</pre>
+
+<p><code><span class="comment">The following is related to "Variables" section as potential values in assignment.</span>undefined</code> 值在布尔类型环境中会被当作 <code>false</code> 。例如,下面的代码将会执行函数 <code>myFunction</code>,因为数组 <code>myArray</code> 中的元素未被赋值:</p>
+
+<pre class="brush: js notranslate">var myArray = [];
+if (!myArray[0])   myFunction();
+</pre>
+
+<p>数值类型环境中 <code>undefined</code> 值会被转换为 <code>NaN</code>。</p>
+
+<pre class="brush: js notranslate">var a;
+a + 2; // 计算为 NaN
+</pre>
+
+<p>当你对一个 <code>null</code> 变量求值时,空值 <code>null</code> 在数值类型环境中会被当作0来对待,而布尔类型环境中会被当作 <code>false</code>。例如:</p>
+
+<pre class="brush: js notranslate">var n = null;
+console.log(n * 32); // 在控制台中会显示 0
+</pre>
+
+<h3 id="变量的作用域">变量的作用域</h3>
+
+<p>在函数之外声明的变量,叫做<em>全局</em>变量,因为它可被当前文档中的任何其他代码所访问。在函数内部声明的变量,叫做<em>局部</em>变量,因为它只能在当前函数的内部访问。</p>
+
+<p>ECMAScript 6 之前的 JavaScript 没有 <a href="https://developer.mozilla.org/zh-CN/docs/JavaScript/Guide/Statements#Block_Statement">语句块</a> 作用域;相反,语句块中声明的变量将成为语句块所在函数(或全局作用域)的局部变量。例如,如下的代码将在控制台输出 5,因为 <code>x</code> 的作用域是声明了 <code>x</code> 的那个函数(或全局范围),而不是 <code>if</code> 语句块。</p>
+
+<pre class="brush: js notranslate">if (true) {
+ var x = 5;
+}
+console.log(x); // 5
+</pre>
+
+<p>如果使用 ECMAScript 6 中的 <code>let</code> 声明,上述行为将发生变化。</p>
+
+<pre class="brush: js notranslate">if (true) {
+ let y = 5;
+}
+console.log(y); // ReferenceError: y 没有被声明</pre>
+
+<h3 id="变量提升">变量提升</h3>
+
+<p>JavaScript 变量的另一个不同寻常的地方是,你可以先使用变量稍后再声明变量而不会引发异常。这一概念称为变量提升;JavaScript 变量感觉上是被“提升”或移到了函数或语句的最前面。但是,提升后的变量将返回 <span style="font-family: courier new,andale mono,monospace;">undefined</span> 值。因此在使用或引用某个变量之后进行声明和初始化操作,这个被提升的变量仍将返回 undefined 值。</p>
+
+<pre class="brush: js notranslate">/**
+ * 例子1
+ */
+console.log(x === undefined); // true
+var x = 3;
+
+
+/**
+ * 例子2
+ */
+// will return a value of undefined
+var myvar = "my value";
+
+(function() {
+ console.log(myvar); // undefined
+ var myvar = "local value";
+})();
+</pre>
+
+<p>上面的例子,也可写作:</p>
+
+<pre class="brush: js notranslate">/**
+ * 例子1
+ */
+var x;
+console.log(x === undefined); // true
+x = 3;
+
+/**
+ * 例子2
+ */
+var myvar = "my value";
+
+(function() {
+ var myvar;
+ console.log(myvar); // undefined
+ myvar = "local value";
+})();</pre>
+
+<p>由于存在变量提升,一个函数中所有的<code>var</code>语句应尽可能地放在接近函数顶部的地方。这个习惯将大大提升代码的清晰度。</p>
+
+<p>在 ECMAScript 6 中,let(const)同样<strong>会被提升</strong>变量到代码块的顶部但是不会被赋予初始值。在变量声明之前引用这个变量,将抛出引用错误(ReferenceError)。这个变量将从代码块一开始的时候就处在一个“暂时性死区”,直到这个变量被声明为止。</p>
+
+<pre class="brush: js notranslate">console.log(x); // ReferenceError
+let x = 3;</pre>
+
+<h3 id="函数提升">函数提升</h3>
+
+<p>对于函数来说,只有函数声明会被提升到顶部,而函数表达式不会被提升。</p>
+
+<pre class="brush: js notranslate">/* 函数声明 */
+
+foo(); // "bar"
+
+function foo() {
+ console.log("bar");
+}
+
+
+/* 函数表达式 */
+
+baz(); // 类型错误:baz 不是一个函数
+
+var baz = function() {
+ console.log("bar2");
+};</pre>
+
+<h3 id="全局变量">全局变量</h3>
+
+<p><span class="comment">need links to pages discussing scope chains and the global object</span> 实际上,全局变量是<em>全局对象</em>的属性。在网页中,(译注:缺省的)全局对象是 <code>window</code> ,所以你可以用形如 <code>window.</code><em><code>variable</code> </em>的语法来设置和访问全局变量。</p>
+
+<p>因此,你可以通过指定 window 或 frame 的名字,在当前 window 或 frame 访问另一个 window 或 frame 中声明的变量。例如,在文档里声明一个叫 <code>phoneNumber</code> 的变量,那么你就可以在子框架里使用 <code>parent.phoneNumber</code> 的方式来引用它。</p>
+
+<h3 id="常量Constants">常量(Constants)</h3>
+
+<p>你可以用关键字 <code>const</code> 创建一个只读的常量。常量标识符的命名规则和变量相同:必须以字母、下划线(_)或美元符号($)开头并可以包含有字母、数字或下划线。</p>
+
+<pre class="brush: js notranslate">const PI = 3.14;
+</pre>
+
+<p>常量不可以通过重新赋值改变其值,也不可以在代码运行时重新声明。它必须被初始化为某个值。</p>
+
+<p>常量的作用域规则与 <code>let</code> 块级作用域变量相同。若省略<code>const</code>关键字,则该标识符将被视为变量。</p>
+
+<p>在同一作用域中,不能使用与变量名或函数名相同的名字来命名常量。例如:</p>
+
+<pre class="brush: js notranslate">// 这会造成错误
+function f() {};
+const f = 5;
+
+// 这也会造成错误
+function f() {
+ const g = 5;
+ var g;
+
+ //语句
+}
+</pre>
+
+<p>然而,对象属性被赋值为常量是不受保护的,所以下面的语句执行时不会产生错误。</p>
+
+<pre class="brush: js notranslate">const MY_OBJECT = {"key": "value"};
+MY_OBJECT.key = "otherValue";</pre>
+
+<p>同样的,数组的被定义为常量也是不受保护的,所以下面的语句执行时也不会产生错误。</p>
+
+<pre class="brush: js notranslate">const MY_ARRAY = ['HTML','CSS'];
+MY_ARRAY.push('JAVASCRIPT');
+console.log(MY_ARRAY); //logs ['HTML','CSS','JAVASCRIPT'];
+</pre>
+
+<h2 id="数据结构和类型">数据结构和类型</h2>
+
+<h3 id="数据类型">数据类型</h3>
+
+<p>最新的 ECMAScript 标准定义了8种数据类型:</p>
+
+<ul>
+ <li>七种基本数据类型:
+ <ul>
+ <li>布尔值(Boolean),有2个值分别是:<code>true</code> 和 <code>false</code>.</li>
+ <li>null , 一个表明 null 值的特殊关键字。 JavaScript 是大小写敏感的,因此 <code>null</code> 与 <code>Null</code>、<code>NULL</code>或变体完全不同。</li>
+ <li>undefined ,和 null 一样是一个特殊的关键字,undefined 表示变量未赋值时的属性。</li>
+ <li>数字(Number),整数或浮点数,例如: <code>42</code> 或者 <code>3.14159</code>。</li>
+ <li>任意精度的整数 (BigInt) ,可以安全地存储和操作大整数,甚至可以超过数字的安全整数限制。</li>
+ <li>字符串(String),字符串是一串表示文本值的字符序列,例如:"Howdy" 。</li>
+ <li>代表(Symbol) ( 在 ECMAScript 6 中新添加的类型).。一种实例是唯一且不可改变的数据类型。</li>
+ </ul>
+ </li>
+ <li>以及对象(Object)。</li>
+</ul>
+
+<p>虽然这些数据类型相对来说比较少,但是通过他们你可以在程序中开发有用的功能。对象(<a href="https://developer.mozilla.org/zh-CN/docs/JavaScript/Reference/Global_Objects/Object" title="zh-CN/docs/JavaScript/Reference/Global Objects/Object">Objects</a>)和函数(<a href="https://developer.mozilla.org/zh-CN/docs/JavaScript/Reference/Global_Objects/Function" title="zh-CN/docs/JavaScript/Reference/Global Objects/Function">functions</a>)是这门语言的另外两个基本元素。你可以把对象当作存放值的一个命名容器,然后将函数当作你的程序能够执行的步骤。</p>
+
+<h3 id="数据类型的转换">数据类型的转换</h3>
+
+<p>JavaScript是一种动态类型语言(dynamically typed language)。这意味着你在声明变量时可以不必指定数据类型,而数据类型会在代码执行时会根据需要自动转换。因此,你可以按照如下方式来定义变量:</p>
+
+<pre class="brush: js notranslate">var answer = 42;
+</pre>
+
+<p>然后,你还可以给同一个变量赋予一个字符串值,例如:</p>
+
+<pre class="brush: js notranslate">answer = "Thanks for all the fish...";</pre>
+
+<p>因为 JavaScript 是动态类型的,这种赋值方式并不会提示出错。</p>
+
+<p>在包含的数字和字符串的表达式中使用加法运算符(+),JavaScript 会把数字转换成字符串。例如,观察以下语句:</p>
+
+<pre class="brush: js notranslate">x = "The answer is " + 42 // "The answer is 42"
+y = 42 + " is the answer" // "42 is the answer"
+</pre>
+
+<p>在涉及其它运算符(译注:如下面的减号'-')时,JavaScript语言不会把数字变为字符串。例如(译注:第一例是数学运算,第二例是字符串运算):</p>
+
+<pre class="brush: js notranslate">"37" - 7 // 30
+"37" + 7 // "377"
+</pre>
+
+<h3 id="字符串转换为数字">字符串转换为数字</h3>
+
+<p>有一些方法可以将内存中表示一个数字的字符串转换为对应的数字。</p>
+
+<h4 id="parseInt和parseFloat"><code>parseInt()</code>和<code>parseFloat()</code></h4>
+
+<p>参见:<code><a href="https://developer.mozilla.org/zh-CN/docs/JavaScript/Reference/Global_Objects/parseInt" title="zh-CN/docs/JavaScript/Reference/Global Objects/parseInt">parseInt()</a></code>和<code><a href="https://developer.mozilla.org/zh-CN/docs/JavaScript/Reference/Global_Objects/parseFloat" title="zh-CN/docs/JavaScript/Reference/Global Objects/parseFloat">parseFloat()</a></code>的相关页面。</p>
+
+<p><code> parseInt </code>方法只能返回整数,所以使用它会丢失小数部分。另外,调用 parseInt 时最好总是带上进制(radix) 参数,这个参数用于指定使用哪一种进制。</p>
+
+<p>将字符串转换为数字的另一种方法是使用一元<strong>加法运算符</strong>。</p>
+
+<pre class="brush: js notranslate">"1.1" + "1.1" = "1.11.1"
+(+"1.1") + (+"1.1") = 2.2
+// 注意:加入括号为清楚起见,不是必需的。
+</pre>
+
+<h2 id="字面量_Literals">字面量 (Literals)</h2>
+
+<p>(译注:字面量是由语法表达式定义的常量;或,通过由一定字词组成的语词表达式定义的常量)</p>
+
+<p>在JavaScript中,你可以使用各种字面量。这些字面量是脚本中按字面意思给出的固定的值,而不是变量。(译注:字面量是常量,其值是固定的,而且在程序脚本运行中不可更改,比如<em>false</em>,3.1415,thisIsStringOfHelloworld<em> </em>,invokedFunction: myFunction("myArgument")。本节将介绍以下类型的字面量:</p>
+
+<ul>
+ <li>{{anch("数组字面量(Array literals)")}}</li>
+ <li>{{anch("布尔字面量(Boolean literals)")}}</li>
+ <li>{{anch("浮点数字面量(Floating-point literals)")}}</li>
+ <li>{{anch("整数(Integers)")}}</li>
+ <li>{{anch("对象字面量(Object literals)")}}</li>
+ <li>{{anch("RegExp literals")}}</li>
+ <li>{{anch("字符串字面量(String literals)")}}</li>
+</ul>
+
+<h3 id="数组字面量_Array_literals">数组字面量 (Array literals)</h3>
+
+<p>数组字面值是一个封闭在方括号对([])中的包含有零个或多个表达式的列表,其中每个表达式代表数组的一个元素。当你使用数组字面值创建一个数组时,该数组将会以指定的值作为其元素进行初始化,而其长度被设定为元素的个数。</p>
+
+<p>下面的示例用3个元素生成数组<code>coffees</code>,它的长度是3。</p>
+
+<pre class="brush: js notranslate">var coffees = ["French Roast", "Colombian", "Kona"];
+
+var a=[3];
+
+console.log(a.length); // 1
+
+console.log(a[0]); // 3</pre>
+
+<div class="note">
+<p><strong>注意</strong><strong> </strong>这里的数组字面值也是一种对象初始化器。参考<a href="https://developer.mozilla.org/zh-CN/docs/JavaScript/Guide/Working_with_Objects#Using_Object_Initializers" title="zh-CN/docs/JavaScript/Guide/Working with Objects#Using Object Initializers">对象初始化器的使用</a>。</p>
+</div>
+
+<p>若在顶层(全局)脚本里用字面值创建数组,JavaScript语言将会在每次对包含该数组字面值的表达式求值时解释该数组。另一方面,在函数中使用的数组,将在每次调用函数时都会被创建一次。</p>
+
+<p>数组字面值同时也是数组对象。有关数组对象的详情请参见<a href="https://developer.mozilla.org/zh-CN/docs/JavaScript/Guide/Predefined_Core_Objects#Array_Object">数组对象</a>一文。</p>
+
+<h4 id="数组字面值中的多余逗号">数组字面值中的多余逗号</h4>
+
+<p>(译注:声明时)你不必列举数组字面值中的所有元素。若你在同一行中连写两个逗号(,),数组中就会产生一个没有被指定的元素,其初始值是<code>undefined</code>。以下示例创建了一个名为<code>fish</code>的数组:</p>
+
+<pre class="brush: js notranslate">var fish = ["Lion", , "Angel"];
+</pre>
+
+<p>在这个数组中,有两个已被赋值的元素,和一个空元素(fish[0]是"Lion",fish[1]是undefined,而fish[2]是"Angel";译注:此时数组的长度属性fish.length是3)。</p>
+
+<p>如果你在元素列表的尾部添加了一个逗号,它将会被忽略。在下面的例子中,数组的长度是3,并不存在myList[3]这个元素(译注:这是指数组的第4个元素噢,作者是在帮大家复习数组元素的排序命名方法)。元素列表中其它所有的逗号都表示一个新元素(的开始)。</p>
+
+<div class="note">
+<p><strong>注意:</strong>尾部的逗号在早期版本的浏览器中会产生错误,因而编程时的最佳实践方式就是移除它们。</p>
+</div>
+
+<p>(译注:而“现代”的浏览器似乎鼓励这种方式,这也很好解释原因。尾部逗号可以减少向数组的最后添加元素时,因为忘记为这最后一个元素加逗号 所造成的错误。)</p>
+
+<pre class="brush: js notranslate">var myList = ['home', , 'school', ];
+</pre>
+
+<p>在下面的例子中,数组的长度是4,元素<code>myList[0]</code>和<code>myList[2]</code>缺失(译注:没被赋值,因而是undefined)。</p>
+
+<pre class="brush: js notranslate">var myList = [ , 'home', , 'school'];
+</pre>
+
+<p>再看一个例子。在这里,该数组的长度是4,元素<code>myList[1]</code>和<code>myList[3]</code>被漏掉了。(但是)只有最后的那个逗号被忽略。</p>
+
+<pre class="brush: js notranslate">var myList = ['home', , 'school', , ];
+</pre>
+
+<p>理解多余的逗号(在脚本运行时会被如何处理)的含义,对于从语言层面理解JavaScript是十分重要的。但是,在你自己写代码时:<strong>显式地将缺失的元素声明为<code>undefined</code>,将大大提高你的代码的清晰度和可维护性</strong>。</p>
+
+<h3 id="布尔字面量_Boolean_literals">布尔字面量 (Boolean literals)</h3>
+
+<p>(译注:即逻辑字面量)</p>
+
+<p>布尔类型有两种字面量:<code>true</code>和<code>false</code>。</p>
+
+<p>不要混淆作为布尔对象的真和假与布尔类型的原始值true和false。<span class="short_text" id="result_box" lang="zh-CN"><span>布尔对象是原始</span><span>布尔</span><span>数据类型的一个包装器</span><span>。参见</span></span><span class="short_text" id="result_box" lang="zh-CN"><span><a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Boolean" title="zh-CN/docs/JavaScript/Guide/Predefined Core Objects#Boolean Object"> 布尔对象</a>。</span></span></p>
+
+<h3 id="整数_Integers">整数 (Integers)</h3>
+
+<p>(译注:原文如此,没写成“整数字面量”,这里指的是整数字面量。)</p>
+
+<p>整数可以用十进制(基数为10)、十六进制(基数为16)、八进制(基数为8)以及二进制(基数为2)表示。</p>
+
+<ul>
+ <li><span class="short_text" id="result_box" lang="zh-CN"><span>十进制整数字面量由一串数字序列组成</span><span>,且没有前缀</span><span>0</span><span>。</span></span></li>
+ <li><span class="short_text" id="result_box" lang="zh-CN"><span>八进制的整数以 0(或</span></span>0O、0o)开头,<span class="short_text" lang="zh-CN"><span>只能包括</span><span>数字0-7</span><span>。</span></span></li>
+ <li><span class="short_text" id="result_box" lang="zh-CN"><span>十六进制整数以0x(或0X)开头,</span><span>可以包含</span><span>数字(0-9)</span><span>和</span><span>字母 a~f 或 A~</span><span>F</span><span>。</span></span></li>
+ <li><span class="short_text" id="result_box" lang="zh-CN"><span>二进制整数以0b(或0B)开头,只能包含数字</span><span>0和1。</span></span></li>
+</ul>
+
+<p>严格模式下,八进制整数字面量必须以0o或0O开头,而不能以0开头。</p>
+
+<p>整数字面量举例:</p>
+
+<pre class="notranslate"><code>0, 117 and -345 (十进制, 基数为10)
+015, 0001 and -0o77 (八进制, 基数为8)
+0x1123, 0x00111 and -0xF1A7 (十六进制, 基数为16或"hex")
+0b11, 0b0011 and -0b11 (二进制, 基数为2)</code></pre>
+
+<h3 id="浮点数字面量_Floating-point_literals">浮点数字面量 (Floating-point literals)</h3>
+
+<p>浮点数字面值可以有以下的组成部分:</p>
+
+<ul>
+ <li><span class="short_text" id="result_box" lang="zh-CN"><span>一个十进制</span><span>整数,可以</span><span>带正负号(</span><span>即前缀</span><span class="atn">“+”</span><span class="atn">或“ - ”</span><span>)</span><span>,</span></span></li>
+ <li>小数点(“.”),</li>
+ <li>小数部分(由一串十进制数表示),</li>
+ <li>指数部分。</li>
+</ul>
+
+<p>指数部分以“e”或“E”开头,后面跟着一个整数,可以有正负号(即前缀“+”或“-”)。浮点数字面量至少有一位数字,而且必须带小数点或者“e”(大写“E”也可)。</p>
+
+<p>简言之,其语法是:</p>
+
+<pre class="brush: js notranslate"><code class="language-html">[(+|-)][digits][.digits][(E|e)[(+|-)]digits]</code></pre>
+
+<p>例如:</p>
+
+<pre class="brush: js notranslate">3.14
+-.2345789 // -0.23456789
+-3.12e+12 // -3.12*10<sup>12</sup>
+.1e-23 // 0.1*10<sup>-23</sup>=10<sup>-24</sup>=1e-24
+</pre>
+
+<h3 id="对象字面量_Object_literals">对象字面量 (Object literals)</h3>
+
+<p>对象字面值是封闭在花括号对({})中的一个对象的零个或多个"属性名-值"对的(元素)列表。你不能在一条语句的开头就使用对象字面值,这将导致错误或产生超出预料的行为, 因为此时左花括号({)会被认为是一个语句块的起始符号。(译者:这 里需要对语句statement、块block等基本名词的解释)</p>
+
+<p>以下是一个对象字面值的例子。对象car的第一个元素(译注:即一个属性/值对)定义了属性myCar;第二个元素,属性getCar,引用了一个函数(即CarTypes("Honda"));第三个元素,属性special,使用了一个已有的变量(即Sales)。</p>
+
+<pre class="brush: js notranslate">var Sales = "Toyota";
+
+function CarTypes(name) {
+ return (name === "Honda") ?
+ name :
+ "Sorry, we don't sell " + name + "." ;
+}
+
+var car = { myCar: "Saturn", getCar: CarTypes("Honda"), special: Sales };
+
+console.log(car.myCar); // Saturn
+console.log(car.getCar); // Honda
+console.log(car.special); // Toyota
+</pre>
+
+<p>更进一步的,你可以使用数字或字符串字面值作为属性的名字,或者在另一个字面值内嵌套上一个字面值。如下的示例中使用了这些可选项。</p>
+
+<pre class="brush: js notranslate">var car = { manyCars: {a: "Saab", "b": "Jeep"}, 7: "Mazda" };
+
+console.log(car.manyCars.b); // Jeep
+console.log(car[7]); // Mazda
+</pre>
+
+<p>对象属性名字可以是任意字符串,包括空串。如果对象属性名字不是合法的javascript标识符,它必须用""包裹。属性的名字不合法,那么便不能用.访问属性值,而是通过类数组标记("[]")访问和赋值。</p>
+
+<pre class="brush: js notranslate">var unusualPropertyNames = {
+ "": "An empty string",
+ "!": "Bang!"
+}
+console.log(unusualPropertyNames.""); // 语法错误: Unexpected string
+console.log(unusualPropertyNames[""]); // An empty string
+console.log(unusualPropertyNames.!); // 语法错误: Unexpected token !
+console.log(unusualPropertyNames["!"]); // Bang!</pre>
+
+<h4 id="增强的对象字面量_Enhanced_Object_literals">增强的对象字面量 (Enhanced Object literals)</h4>
+
+<p>在ES2015,对象字面值扩展支持在创建时设置原型,简写了 foo: foo 形式的属性赋值,方法定义,支持父方法调用,以及使用表达式动态计算属性名。总之,这些也使对象字面值和类声明更加紧密地联系起来,让基于对象的设计从这些便利中更加受益。</p>
+
+<pre class="brush: js line-numbers language-js notranslate"><code class="language-js"><span class="keyword token">var</span> obj <span class="operator token">=</span> <span class="punctuation token">{</span>
+ <span class="comment token">// __proto__</span>
+ __proto__<span class="punctuation token">:</span> theProtoObj<span class="punctuation token">,</span>
+ <span class="comment token">// Shorthand for ‘handler: handler’</span>
+ handler<span class="punctuation token">,</span>
+ <span class="comment token">// Methods</span>
+ <span class="function token">toString</span><span class="punctuation token">(</span><span class="punctuation token">)</span> <span class="punctuation token">{</span>
+ <span class="comment token">// Super calls</span>
+ <span class="keyword token">return</span> <span class="string token">"d "</span> <span class="operator token">+</span> <span class="keyword token">super</span><span class="punctuation token">.</span><span class="function token">toString</span><span class="punctuation token">(</span><span class="punctuation token">)</span><span class="punctuation token">;</span>
+ <span class="punctuation token">}</span><span class="punctuation token">,</span>
+ <span class="comment token">// Computed (dynamic) property names</span>
+ <span class="punctuation token">[</span> <span class="string token">'prop_'</span> <span class="operator token">+</span> <span class="punctuation token">(</span><span class="punctuation token">(</span><span class="punctuation token">)</span> <span class="operator token">=</span><span class="operator token">&gt;</span> <span class="number token">42</span><span class="punctuation token">)</span><span class="punctuation token">(</span><span class="punctuation token">)</span> <span class="punctuation token">]</span><span class="punctuation token">:</span> <span class="number token">42</span>
+<span class="punctuation token">}</span><span class="punctuation token">;</span></code></pre>
+
+<p>请注意:</p>
+
+<pre class="brush: js notranslate">var foo = {a: "alpha", 2: "two"};
+console.log(foo.a); // alpha
+console.log(foo[2]); // two
+//console.log(foo.2); // SyntaxError: missing ) after argument list
+//console.log(foo[a]); // ReferenceError: a is not defined
+console.log(foo["a"]); // alpha
+console.log(foo["2"]); // two</pre>
+
+<h3 id="RegExp_字面值">RegExp 字面值</h3>
+
+<p>一个正则表达式是字符被斜线(译注:正斜杠“/”)围成的表达式。下面是一个正则表达式文字的一个例子。</p>
+
+<pre class="brush: js line-numbers language-js notranslate"><code class="language-js"><span class="keyword token">var</span> re <span class="operator token">=</span> <span class="regex token">/ab+c/</span><span class="punctuation token">;</span></code></pre>
+
+<h3 id="字符串字面量_String_literals">字符串字面量 (String literals)</h3>
+
+<p>字符串字面量是由双引号(")对或单引号(')括起来的零个或多个字符。字符串被限定在同种引号之间;也即,必须是成对单引号或成对双引号。下面的例子都是字符串字面值:</p>
+
+<pre class="brush: js notranslate">"foo"
+'bar'
+"1234"
+"one line \n another line"
+"John's cat"</pre>
+
+<p>你可以在字符串字面值上使用字符串对象的所有方法——JavaScript会自动将字符串字面值转换为一个临时字符串对象,调用该方法,然后废弃掉那个临时的字符串对象。你也能用对字符串字面值使用类似String.length的属性:</p>
+
+<pre class="brush: js notranslate"><code>console.log("John's cat".length)
+// 将打印字符串中的字符个数(包括空格)
+// 结果为:10</code></pre>
+
+<p>在ES2015中,还提供了一种模板字面量(template literals),模板字符串提供了一些语法糖来帮你构造字符串。这与Perl、Python还有其他语言中的字符串插值(string interpolation)的特性非常相似。除此之外,你可以在通过模板字符串前添加一个tag来自定义模板字符串的解析过程,这可以用来防止注入攻击,或者用来建立基于字符串的高级数据抽象。</p>
+
+<pre class="brush: js notranslate">// Basic literal string creation
+`In JavaScript '\n' is a line-feed.`
+
+// Multiline strings
+`In JavaScript this is
+ not legal.`
+
+// String interpolation
+var name = "Bob", time = "today";
+`Hello ${name}, how are you ${time}?`
+
+// Construct an HTTP request prefix is used to interpret the replacements and construction
+POST`http://foo.org/bar?a=${a}&amp;b=${b}
+ Content-Type: application/json
+ X-Credentials: ${credentials}
+ { "foo": ${foo},
+ "bar": ${bar}}`(myOnReadyStateChangeHandler);
+</pre>
+
+<p>除非有特别需要使用字符串对象,否则,你应当始终使用字符串字面值。要查看字符串对象的有关细节,请参见<a href="https://developer.mozilla.org/zh-CN/docs/JavaScript/Guide/Predefined_Core_Objects#String_Object" title="zh-CN/docs/JavaScript/Guide/Predefined Core Objects#String Object">字符串对象</a>。</p>
+
+<h4 id="在字符串中使用的特殊字符">在字符串中使用的特殊字符</h4>
+
+<p>作为一般字符的扩展,你可以在字符串中使用特殊字符,如下例所示。</p>
+
+<pre class="brush: js notranslate">"one line \n another line"
+</pre>
+
+<p>以下表格列举了你能在JavaScript的字符串中使用的特殊字符。</p>
+
+<table class="standard-table">
+ <caption>表 2.1 JavaScript 特殊字符</caption>
+ <thead>
+ <tr>
+ <th scope="col">字符</th>
+ <th scope="col">意思</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>\0</td>
+ <td>Null字节</td>
+ </tr>
+ <tr>
+ <td>\b</td>
+ <td>退格符</td>
+ </tr>
+ <tr>
+ <td>\f</td>
+ <td>换页符</td>
+ </tr>
+ <tr>
+ <td>\n</td>
+ <td>换行符</td>
+ </tr>
+ <tr>
+ <td>\r</td>
+ <td>回车符</td>
+ </tr>
+ <tr>
+ <td>\t</td>
+ <td>Tab (制表符)</td>
+ </tr>
+ <tr>
+ <td>\v</td>
+ <td>垂直制表符</td>
+ </tr>
+ <tr>
+ <td>\'</td>
+ <td>单引号</td>
+ </tr>
+ <tr>
+ <td>\"</td>
+ <td>双引号</td>
+ </tr>
+ <tr>
+ <td>\\</td>
+ <td>反斜杠字符(\)</td>
+ </tr>
+ <tr>
+ <td>\<em>XXX</em></td>
+ <td>由从0到377最多三位八进制数<em>XXX</em>表示的 Latin-1 字符。例如,\251是版权符号的八进制序列。</td>
+ </tr>
+ <tr>
+ <td>\x<em>XX</em></td>
+ <td>由从00和FF的两位十六进制数字XX表示的Latin-1字符。例如,\ xA9是版权符号的十六进制序列。</td>
+ </tr>
+ <tr>
+ <td><em>\uXXXX</em></td>
+ <td>由四位十六进制数字XXXX表示的Unicode字符。例如,\ u00A9是版权符号的Unicode序列。见<a href="/en-US/docs/Web/JavaScript/Reference/Lexical_grammar#String_literals">Unicode escape sequences</a> (Unicode 转义字符).</td>
+ </tr>
+ <tr>
+ <td>\u<em>{XXXXX}</em></td>
+ <td>Unicode代码点 (code point) 转义字符。例如,\u{2F804} 相当于Unicode转义字符 \uD87E\uDC04的简写。</td>
+ </tr>
+ </tbody>
+</table>
+
+<p>译注:严格模式下,不能使用八进制转义字符。</p>
+
+<h4 id="转义字符">转义字符</h4>
+
+<p>对于那些未出现在表2.1中的字符,其所带的前导反斜线'\'将被忽略。但是,这一用法已被废弃,应当避免使用。</p>
+
+<p>通过在引号前加上反斜线'\',可以在字符串中插入引号,这就是<em>引号转义</em>。例如:</p>
+
+<pre class="brush: js notranslate">var quote = "He read \"The Cremation of Sam McGee\" by R.W. Service.";
+console.log(quote);
+</pre>
+
+<p>代码的运行结果为:</p>
+
+<pre class="brush: js notranslate">He read "The Cremation of Sam McGee" by R.W. Service.
+</pre>
+
+<p>要在字符串中插入'\'字面值,必须转义反斜线。例如,要把文件路径 c:\temp 赋值给一个字符串,可以采用如下方式:</p>
+
+<pre class="brush: js notranslate">var home = "c:\\temp";
+</pre>
+
+<p>也可以在换行之前加上反斜线以转义换行(译注:实际上就是一条语句拆成多行书写),这样反斜线和换行都不会出现在字符串的值中。</p>
+
+<pre class="brush: js notranslate">var str = "this string \
+is broken \
+across multiple\
+lines."
+<span class="objectBox objectBox-text">console.log(str);</span> // <span class="objectBox objectBox-text">this string is broken across multiplelines.</span>
+</pre>
+
+<p>Javascript没有“heredoc”语法,但可以用行末的换行符转义和转义的换行来近似实现 </p>
+
+<pre class="brush: js notranslate">var poem =
+"Roses are red,\n\
+Violets are blue.\n\
+Sugar is sweet,\n\
+and so is foo."
+</pre>
+
+<p>ECMAScript 2015 增加了一种新的字面量,叫做模板字面量 <strong><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/template_strings" rel="noreferrer">template literals</a>。</strong>它包含一些新特征,包括了多行字符串!</p>
+
+<pre class="brush: js notranslate">var poem =
+`Roses are red,
+Violets are blue.
+Sugar is sweet,
+and so is foo.`</pre>
+
+<h2 id="更多信息">更多信息</h2>
+
+<p>?本章重点包括声明和类型的基本语法。学习更多关于的JavaScript语言,可参见本站以下章节:</p>
+
+<ul>
+ <li><a href="/zh-CN/docs/Web/JavaScript/Guide/Control_flow_and_error_handling">流程控制与错误处理</a></li>
+ <li><a href="/zh-CN/docs/Web/JavaScript/Guide/Loops_and_iteration">循环与迭代</a></li>
+ <li><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Functions">?函数</a><a href="/zh-CN/docs/Web/JavaScript/Guide/Functions">函数</a></li>
+ <li><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators">?</a><a href="/zh-CN/docs/Web/JavaScript/Guide/Expressions_and_Operators">表达式与运算符</a></li>
+</ul>
+
+<p>下一章,流程控制与错误处理</p>
+
+<p>{{PreviousNext("Web/JavaScript/Guide/Introduction", "Web/JavaScript/Guide/Control_flow_and_error_handling")}}</p>
diff --git a/files/zh-cn/web/javascript/guide/index.html b/files/zh-cn/web/javascript/guide/index.html
new file mode 100644
index 0000000000..d1ae6683bd
--- /dev/null
+++ b/files/zh-cn/web/javascript/guide/index.html
@@ -0,0 +1,135 @@
+---
+title: JavaScript 指南
+slug: Web/JavaScript/Guide
+tags:
+ - Guide
+ - JavaScript
+translation_of: Web/JavaScript/Guide
+---
+<div>{{jsSidebar("JavaScript Guide")}}</div>
+
+<p class="summary">JavaScript 指南向你介绍如何使用 <a href="/zh-CN/docs/Web/JavaScript">JavaScript</a>,并且给出了语言概述。如果你需要了解某些语言特性的详细信息,请参阅 <a href="/zh-CN/docs/Web/JavaScript/Reference">JavaScript 参考</a>。</p>
+
+<h2 id="章节">章节</h2>
+
+<p>本指南分为以下章节:</p>
+
+<ul class="card-grid">
+ <li><span><a href="/zh-CN/docs/Web/JavaScript/Guide/Introduction">介绍</a></span>
+
+ <p><a href="/zh-CN/docs/Web/JavaScript/Guide/Introduction#What_is_JavaScript.3F">关于这份指南</a><br>
+ <a href="/zh-CN/docs/Web/JavaScript/Guide/Introduction#什么是_JavaScript">关于 JavaScript</a><br>
+ <a href="/zh-CN/docs/Web/JavaScript/Guide/Introduction#JavaScript_and_Java">JavaScript 与 Java</a><br>
+ <a href="/zh-CN/docs/Web/JavaScript/Guide/Introduction#JavaScript_and_the_ECMAScript_Specification">ECMAScript</a><br>
+ <a href="/zh-CN/docs/Web/JavaScript/Guide/Introduction#Getting_started_with_JavaScript">工具</a><br>
+ <a href="/zh-CN/docs/Web/JavaScript/Guide/Introduction#Hello_world">Hello World</a></p>
+ </li>
+ <li><span><a href="/zh-CN/docs/Web/JavaScript/Guide/Grammar_and_types">语法与数据类型</a></span>
+ <p><a href="/zh-CN/docs/Web/JavaScript/Guide/Grammar_and_types#基础">基本语法与注释</a><br>
+ <a href="/zh-CN/docs/Web/JavaScript/Guide/Grammar_and_types#声明">声明</a><br>
+ <a href="/zh-CN/docs/Web/JavaScript/Guide/Grammar_and_types#变量的作用域">变量作用域</a><br>
+ <a href="/zh-CN/docs/Web/JavaScript/Guide/Grammar_and_types#变量提升">变量提升</a><br>
+ <a href="/zh-CN/docs/Web/JavaScript/Guide/Grammar_and_types#数据结构和类型">数据结构和类型</a><br>
+ <a href="/zh-CN/docs/Web/JavaScript/Guide/Grammar_and_types#字面量_(Literals)">字面量</a></p>
+ </li>
+ <li><span><a href="/zh-CN/docs/Web/JavaScript/Guide/Control_flow_and_error_handling">控制流与错误处理</a></span>
+ <p><a href="/zh-CN/docs/Web/JavaScript/Guide/Control_flow_and_error_handling#if...else_语句"><code>if...else</code></a><br>
+ <a href="/zh-CN/docs/Web/JavaScript/Guide/Control_flow_and_error_handling#switch_语句"><code>switch</code></a><br>
+ <a href="/zh-CN/docs/Web/JavaScript/Guide/Control_flow_and_error_handling#异常处理语句"><code>try</code>/<code>catch</code>/<code>throw</code></a><br>
+ <a href="/zh-CN/docs/Web/JavaScript/Guide/Control_flow_and_error_handling#使用Error对象">Error 对象</a></p>
+ </li>
+ <li><span><a href="/zh-CN/docs/Web/JavaScript/Guide/Loops_and_iteration">循环与迭代</a></span>
+ <p><a href="/zh-CN/docs/Web/JavaScript/Guide/Loops_and_iteration#for_语句"><code>for</code></a><br>
+ <a href="/zh-CN/docs/Web/JavaScript/Guide/Loops_and_iteration#while_语句"><code>while</code></a><br>
+ <a href="/zh-CN/docs/Web/JavaScript/Guide/Loops_and_iteration#do...while_语句"><code>do...while</code></a><br>
+ <a href="/zh-CN/docs/Web/JavaScript/Guide/Loops_and_iteration#break_语句"><code>break</code></a>/<a href="/zh-CN/docs/Web/JavaScript/Guide/Loops_and_iteration#continue_语句"><code>continue</code></a><br>
+ <a href="/zh-CN/docs/Web/JavaScript/Guide/Loops_and_iteration#for...in_语句"><code>for..in</code></a><br>
+ <a href="/zh-CN/docs/Web/JavaScript/Guide/Loops_and_iteration#for...of_语句"><code>for..of</code></a></p>
+ </li>
+</ul>
+
+<ul class="card-grid">
+ <li><span><a href="/zh-CN/docs/Web/JavaScript/Guide/Functions">函数</a></span>
+
+ <p><a href="/zh-CN/docs/Web/JavaScript/Guide/Functions#定义函数">定义函数</a><br>
+ <a href="/zh-CN/docs/Web/JavaScript/Guide/Functions#调用函数">调用函数</a><br>
+ <a href="/zh-CN/docs/Web/JavaScript/Guide/Functions#函数作用域">函数作用域</a><br>
+ <a href="/zh-CN/docs/Web/JavaScript/Guide/Functions#闭包">闭包</a><br>
+ <a href="/zh-CN/docs/Web/JavaScript/Guide/Functions#使用_arguments_对象">arguments 对象</a> 和 <a href="/zh-CN/docs/Web/JavaScript/Guide/Functions#函数参数">参数</a><br>
+ <a href="/zh-CN/docs/Web/JavaScript/Guide/Functions#箭头函数">箭头函数</a></p>
+ </li>
+ <li><span><a href="/zh-CN/docs/Web/JavaScript/Guide/Expressions_and_Operators">表达式和运算符</a></span>
+ <p><a href="/zh-CN/docs/Web/JavaScript/Guide/Expressions_and_Operators#赋值运算符(Assignment_operators)">赋值</a> &amp; <a href="/zh-CN/docs/Web/JavaScript/Guide/Expressions_and_Operators#比较运算符(Comparison_operators)">比较</a><br>
+ <a href="/zh-CN/docs/Web/JavaScript/Guide/Expressions_and_Operators#算术运算符(Arithmetic_operators)">算术运算符</a><br>
+ <a href="/zh-CN/docs/Web/JavaScript/Guide/Expressions_and_Operators#位运算符(Bitwise_operators)">位运算</a> &amp; <a href="/zh-CN/docs/Web/JavaScript/Guide/Expressions_and_Operators#逻辑运算符(Logical_operators)">逻辑运算符</a><br>
+ <a href="/zh-CN/docs/Web/JavaScript/Guide/Expressions_and_Operators#conditional_operator">条件(三元)运算符</a></p>
+ </li>
+ <li><span><a href="/zh-CN/docs/Web/JavaScript/Guide/Numbers_and_dates">数字与日期</a></span> <a href="/zh-CN/docs/Web/JavaScript/Guide/Numbers_and_dates#数字"><code>Number</code> 字面量</a><br>
+ <a href="/zh-CN/docs/Web/JavaScript/Guide/Numbers_and_dates#数字对象"><code>Number</code> 对象</a><br>
+ <a href="/zh-CN/docs/Web/JavaScript/Guide/Numbers_and_dates#数学对象(Math)"><code>Math</code> 对象</a><br>
+ <a href="/zh-CN/docs/Web/JavaScript/Guide/Numbers_and_dates#日期对象"><code>Date</code> 对象</a></li>
+ <li><span><a href="/zh-CN/docs/Web/JavaScript/Guide/Text_formatting">文本格式化</a></span>
+ <p><a href="/zh-CN/docs/Web/JavaScript/Guide/Text_formatting#字符串">字符串字面量</a><br>
+ <a href="/zh-CN/docs/Web/JavaScript/Guide/Text_formatting#字符串对象">字符串对象</a><br>
+ <a href="/zh-CN/docs/Web/JavaScript/Guide/Text_formatting#多行模板字符串">模版字面量</a><br>
+ <a href="/zh-CN/docs/Web/JavaScript/Guide/Text_formatting#国际化">国际化</a><br>
+ <a href="/zh-CN/docs/Web/JavaScript/Guide/Regular_Expressions">正则表达式</a></p>
+ </li>
+</ul>
+
+<ul class="card-grid">
+ <li><span><a href="/zh-CN/docs/Web/JavaScript/Guide/Indexed_collections">索引集合</a></span>
+
+ <p><a href="/zh-CN/docs/Web/JavaScript/Guide/Indexed_collections#map%E6%95%B0%E7%BB%84">数组</a><br>
+ <a href="/zh-CN/docs/Web/JavaScript/Guide/Indexed_collections#类型化数组(Typed_Arrays_)">类型数组</a></p>
+ </li>
+ <li><span><a href="/zh-CN/docs/Web/JavaScript/Guide/Keyed_collections">带键集合</a></span>
+ <p><a href="/zh-CN/docs/Web/JavaScript/Guide/Keyed_collections#Map对象"><code>Map</code></a><br>
+ <a href="/zh-CN/docs/Web/JavaScript/Guide/Keyed_collections#WeakMap对象"><code>WeakMap</code></a><br>
+ <a href="/zh-CN/docs/Web/JavaScript/Guide/Keyed_collections#Set对象"><code>Set</code></a><br>
+ <a href="/zh-CN/docs/Web/JavaScript/Guide/Keyed_collections#WeakSet对象"><code>WeakSet</code></a></p>
+ </li>
+ <li><span><a href="/zh-CN/docs/Web/JavaScript/Guide/Working_with_Objects">处理对象</a></span>
+ <p><a href="/zh-CN/docs/Web/JavaScript/Guide/Working_with_Objects#%E5%AF%B9%E8%B1%A1%E5%92%8C%E5%B1%9E%E6%80%A7_2">对象和属性</a><br>
+ <a href="/zh-CN/docs/Web/JavaScript/Guide/Working_with_Objects#%E5%88%9B%E5%BB%BA%E6%96%B0%E5%AF%B9%E8%B1%A1">创建对象</a><br>
+ <a href="/zh-CN/docs/Web/JavaScript/Guide/Working_with_Objects#%E5%AE%9A%E4%B9%89%E6%96%B9%E6%B3%95">定义方法</a><br>
+ <a href="/zh-CN/docs/Web/JavaScript/Guide/Working_with_Objects#%E5%AE%9A%E4%B9%89_getters_%E4%B8%8E_setters">getter 和 setter</a></p>
+ </li>
+ <li><span><a href="/zh-CN/docs/Web/JavaScript/Guide/Details_of_the_Object_Model">对象模型的细节</a></span>
+ <p><a href="/zh-CN/docs/Web/JavaScript/Guide/Details_of_the_Object_Model#class-based_vs_prototype-based_languages">基于原型的面向对象编程</a><br>
+ <a href="/zh-CN/docs/Web/JavaScript/Guide/Details_of_the_Object_Model#%E5%88%9B%E5%BB%BA%E5%B1%82%E7%BA%A7%E7%BB%93%E6%9E%84">创建对象层次结构</a><br>
+ <a href="/zh-CN/docs/Web/JavaScript/Guide/Details_of_the_Object_Model#%E5%AF%B9%E8%B1%A1%E7%9A%84%E5%B1%9E%E6%80%A7">继承</a></p>
+ </li>
+</ul>
+
+<ul class="card-grid">
+ <li><span><a href="/zh-CN/docs/Web/JavaScript/Guide/Using_promises">Promises</a></span>
+
+ <p><a href="/zh-CN/docs/Web/JavaScript/Guide/Using_promises#%E7%BA%A6%E5%AE%9A">约定</a><br>
+ <a href="/zh-CN/docs/Web/JavaScript/Guide/Using_promises#%E9%93%BE%E5%BC%8F%E8%B0%83%E7%94%A8">链式调用</a><br>
+ <a href="/zh-CN/docs/Web/JavaScript/Guide/Using_promises#%E9%94%99%E8%AF%AF%E4%BC%A0%E9%80%92">错误传递</a><br>
+ <a href="/zh-CN/docs/Web/JavaScript/Guide/Using_promises#%E7%BB%84%E5%90%88">组合</a><br>
+ <a href="/zh-CN/docs/Web/JavaScript/Guide/Using_promises#%E6%97%B6%E5%BA%8F">时序</a></p>
+ </li>
+ <li><span><a href="/zh-CN/docs/Web/JavaScript/Guide/Iterators_and_Generators">迭代器与生成器</a></span>
+ <p><a href="/zh-CN/docs/Web/JavaScript/Guide/Iterators_and_Generators#%E8%BF%AD%E4%BB%A3%E5%99%A8">迭代器</a><br>
+ <a href="/zh-CN/docs/Web/JavaScript/Guide/Iterators_and_Generators#%E7%94%9F%E6%88%90%E5%99%A8">生成器</a><br>
+ <a href="/zh-CN/docs/Web/JavaScript/Guide/Iterators_and_Generators#%E5%8F%AF%E8%BF%AD%E4%BB%A3%E5%AF%B9%E8%B1%A1">可迭代对象</a></p>
+ </li>
+ <li><span><a href="/zh-CN/docs/Web/JavaScript/Guide/Meta_programming">元编程</a></span>
+ <p><a href="/zh-CN/docs/Web/JavaScript/Guide/Meta_programming#%E4%BB%A3%E7%90%86"><code>Proxy</code></a><br>
+ <a href="/zh-CN/docs/Web/JavaScript/Guide/Meta_programming#%E5%8F%A5%E6%9F%84%E5%92%8C%E9%99%B7%E9%98%B1">Handlers 和 traps</a><br>
+ <a href="/zh-CN/docs/Web/JavaScript/Guide/Meta_programming#%E6%92%A4%E9%94%80_Proxy">撤销 Proxy</a><br>
+ <a href="/zh-CN/docs/Web/JavaScript/Guide/Meta_programming#%E5%8F%8D%E5%B0%84"><code>Reflect</code></a></p>
+ </li>
+ <li><span><a href="/zh-CN/docs/Web/JavaScript/Guide/Modules">JavaScript 模块</a></span>
+ <p><a href="/zh-CN/docs/Web/JavaScript/Guide/Modules#Exporting_module_features">导出模块</a><br>
+ <a href="/zh-CN/docs/Web/JavaScript/Guide/Modules#Importing_features_into_your_script">导入模块</a><br>
+ <a href="/zh-CN/docs/Web/JavaScript/Guide/Modules#Default_exports_versus_named_exports">默认导出</a><br>
+ <a href="/zh-CN/docs/Web/JavaScript/Guide/Modules#Renaming_imports_and_exports">重命名模块</a><br>
+ <a href="/zh-CN/docs/Web/JavaScript/Guide/Modules#Aggregating_modules">合并模块</a><br>
+ <a href="/zh-CN/docs/Web/JavaScript/Guide/Modules#Dynamic_module_loading">动态加载模块</a></p>
+ </li>
+</ul>
+
+<p>{{Next("Web/JavaScript/Guide/Introduction")}}</p>
diff --git a/files/zh-cn/web/javascript/guide/indexed_collections/index.html b/files/zh-cn/web/javascript/guide/indexed_collections/index.html
new file mode 100644
index 0000000000..5dddf74d46
--- /dev/null
+++ b/files/zh-cn/web/javascript/guide/indexed_collections/index.html
@@ -0,0 +1,478 @@
+---
+title: 索引集合类 (Indexed collections)
+slug: Web/JavaScript/Guide/Indexed_collections
+translation_of: Web/JavaScript/Guide/Indexed_collections
+---
+<div>{{jsSidebar("JavaScript Guide")}} {{PreviousNext("Web/JavaScript/Guide/Regular_Expressions", "Web/JavaScript/Guide/Keyed_Collections")}}</div>
+
+<p class="summary">这个章节主要介绍了以索引进行排序的数据集合。包括数组以及类似于数组的数据结构,如<strong style="background-color: #f4f7f8; font-weight: bold;"> {{jsxref("Array")}} </strong>、<strong style="background-color: #f4f7f8; font-weight: bold;">{{jsxref("TypedArray")}} </strong>。</p>
+
+<h2 id="数组对象Array_object"><font face="Courier, Andale Mono, monospace">数组对象(Array object)</font></h2>
+
+<p><font face="Courier, Andale Mono, monospace">数组(array)是一个有序的数据集合,我们可以通过数组名称(name)和索引(index)进行访问。例如,我们定义了一个数组emp,数组中的每个元素包含了一个雇员的名字以及其作为索引的员工号。那么emp[1]将会代表1号员工,emp[2]将会代表2号员工,以此类推。</font></p>
+
+<p>JavaScript中没有明确的数组数据类型。但是,我们可以通过使用内置Array对象和它的方法对数组进行操作。Array对象有很多操作数组的方法,比如合并、反转、排序等。数组对象有一个决定数组长度和使用正则表达式操作其他属性的属性。</p>
+
+<h3 id="创建数组creating_an_array">创建数组(creating an array)</h3>
+
+<p>以下语句创建等效的数组:</p>
+
+<pre class="brush: js notranslate">var arr = new Array(element0, element1, ..., elementN);
+var arr = Array(element0, element1, ..., elementN);
+var arr = [element0, element1, ..., elementN];
+
+// 译者注: var arr=[4] 和 var arr=new Array(4)是不等效的,
+// 后者4指数组长度,所以使用字面值(literal)的方式应该不仅仅是便捷,同时也不易踩坑</pre>
+
+<p><code>element0, element1, ..., elementN</code> 是数组元素的值的列表。当这些值被指定后,数组将被初始化,他们将被作为数组元素。数组的length属性也会被设为参数的个数。</p>
+
+<p>括号语法被称为 "数组字面值" 或 "数组初始化器", 它比其他创建数组的方式更便捷,所以通常是首选。详细内容参见 <a href="/en-US/docs/Web/JavaScript/Guide/Grammar_and_types#Array_literals" title="en-US/docs/JavaScript/Guide/Values, Variables, and Literals#Array Literals">Array literals</a> 。</p>
+
+<p>为了创建一个长度不为0,但是又没有任何元素的数组,可选以下任何一种方式:</p>
+
+<pre class="brush: js notranslate">var arr = new Array(arrayLength);
+var arr = Array(arrayLength);
+
+// 这样有同样的效果
+var arr = [];
+arr.length = arrayLength;
+</pre>
+
+<div class="note">
+<p><strong>注意: </strong>以上代码,数组长度(arrayLength)必须为一个数字(Number)。否则,将会创建一个只有单个(所输入的)元素的数组。 调用 <code>arr.length</code> 会返回数组长度,但是数组实际上包含了空的(<code>undefined</code>)元素。 因此在数组上使用 <code><a href="/en-US/docs/Web/JavaScript/Reference/Statements/for...in">for...in</a></code> 循环,将不会返回任何的值 。</p>
+</div>
+
+<p>除了如上所示创建新定义的变量,数组(array)也可以作为一个属性(property)分配给一个新的或者已存在的对象(object):</p>
+
+<pre class="brush: js notranslate">var obj = {};
+// ...
+obj.prop = [element0, element1, ..., elementN];
+
+// OR
+var obj = {prop: [element0, element1, ...., elementN]}
+</pre>
+
+<p>如果你希望用单个元素初始化一个数组,而这个元素恰好又是数字(<code>Number</code>),那么你必须使用括号语法。当单个的数字(<code>Number</code>)传递给Array()构造函数时,将会被解释为数组长度,并非单个元素。</p>
+
+<pre class="brush: js notranslate">var arr = [42]; // 创建一个只有唯一元素的数组:
+ // the <strong>number</strong> 42.
+var arr = Array(42); // 创建一个没有元素的数组,
+ // 但是数组的长度被设置成42.
+
+// 上面的代码与下面的代码等价
+var arr = [];
+arr.length = 42;
+</pre>
+
+<p>如果N不是一个整数,调用<code>Array(N)</code>将会报<code>RangeError</code>错误, 以下方法说明了这种行为:</p>
+
+<pre class="brush: js notranslate">var arr = Array(9.3); // RangeError: Invalid array length
+</pre>
+
+<p>如果你需要创建任意类型的单元素数组,安全的方式是使用字面值。或者在向数组添加单个元素之前先创建一个空的数组。</p>
+
+<h3 id="填充数组populating_an_array">填充数组(populating an array)</h3>
+
+<p>你可以通过给元素赋值来填充数组,例如:</p>
+
+<pre class="brush: js notranslate">var emp = [];
+emp[0] = "Casey Jones";
+emp[1] = "Phil Lesh";
+emp[2] = "August West";
+</pre>
+
+<div class="note">
+<p><strong>注意:</strong>如果你在以上代码中给数组操作符的是一个非整形数值,那么将作为一个代表数组的对象的属性(property)创建,而非作为数组的元素。</p>
+</div>
+
+<pre class="brush: js notranslate">var arr = [];
+arr[3.4] = "Oranges";
+console.log(arr.length); // 0
+console.log(arr.hasOwnProperty(3.4)); // true
+</pre>
+
+<p>你也可以在创建数组的时候去填充它:</p>
+
+<pre class="brush: js notranslate">var myArray = new Array("Hello", myVar, 3.14159);
+var myArray = ["Mango", "Apple", "Orange"]
+</pre>
+
+<h3 id="引用数组元素referring_to_array_elements">引用数组元素(referring to array elements)</h3>
+
+<p>您通过可以使用元素的序号来引用数组的元素。例如,假设你定义了如下数组:</p>
+
+<pre class="brush: js notranslate">var myArray = ["Wind", "Rain", "Fire"];
+</pre>
+
+<p>你可以用 <code>myArray[0]</code>引用第一个元素,<code>myArray[1]</code>引用第二个元素。元素的索引是从<code>0</code>开始的。</p>
+
+<div class="note">
+<p><strong>注意:</strong>数组操作符(方括号 [ ])也可以用来访问数组的属性(在 JavaScript 中,数组也是对象)。例如:</p>
+</div>
+
+<pre class="brush: js notranslate">var arr = ["one", "two", "three"];
+arr[2]; // three
+arr["length"]; // 3
+</pre>
+
+<h3 id="理解_length">理解 length</h3>
+
+<p>在实施层面, JavaScript实际上是将元素作为标准的对象属性来存储,把数组索引作为属性名。长度属性是特殊的,它总是返回最后一个元素的索引值加1(下例中, Dusty 的索引是30,所以cats.length 返回 30 + 1)。记住, JavaScript 数组索引是基于0的: 他们从0开始,而不是1。这意味着数组长度属性将比最大的索引值大1:</p>
+
+<pre class="brush: js notranslate">var cats = [];
+cats[30] = ['Dusty'];
+console.log(cats.length); // 31
+</pre>
+
+<p>你也可以分配<code>length</code>属性。写一个小于数组元素数量的值会缩短数组,写0会彻底清空数组:</p>
+
+<pre class="brush: js notranslate">var cats = ['Dusty', 'Misty', 'Twiggy'];
+console.log(cats.length); // 3
+
+cats.length = 2;
+console.log(cats); // logs "Dusty,Misty" - Twiggy has been removed
+
+cats.length = 0;
+console.log(cats); // logs nothing; the cats array is empty
+
+cats.length = 3;
+console.log(cats); // [undefined, undefined, undefined]
+</pre>
+
+<h3 id="遍历数组interating_over_array">遍历数组(interating over array)</h3>
+
+<p>遍历数组元素并以某种方式处理每个元素是一个常见的操作。以下是最简单的方式:</p>
+
+<pre class="brush: js notranslate">var colors = ['red', 'green', 'blue'];
+for (var i = 0; i &lt; colors.length; i++) {
+ console.log(colors[i]);
+}
+</pre>
+
+<p>如果你确定数组中没有一个元素的求值是false —— 如果你的数组只包含<a href="/en-US/docs/DOM" title="en-US/docs/DOM">DOM</a>节点,如下,你可以选择一个更高效的土法子:</p>
+
+<pre class="brush: js notranslate">var divs = document.getElementsByTagName('div');
+for (var i = 0, div; div = divs[i]; i++) {
+ /* Process div in some way */
+}
+</pre>
+
+<p>这样避免了检测数组长度的开销,额外的好处是确保了div变量当前在每次循环中都被重新赋值为当前项。</p>
+
+<p>{{jsxref("Array.forEach", "forEach()")}} 方法提供了遍历数组元素的其他方法:</p>
+
+<pre class="brush: js notranslate">var colors = ['red', 'green', 'blue'];
+colors.forEach(function(color) {
+ console.log(color);
+});
+</pre>
+
+<p>被传递给forEach的函数会在数组的每个元素像上执行一次,元素作为参数传递给该函数。未赋值的值不会在forEach循环迭代。</p>
+
+<p>注意,在数组定义时省略的元素不会在forEach遍历时被列出,但是手动赋值为undefined的元素是会被列出的:</p>
+
+<pre class="brush: js notranslate">var array = ['first', 'second', , 'fourth'];
+
+// returns ['first', 'second', 'fourth'];
+array.forEach(function(element) {
+ console.log(element);
+})
+
+if(array[2] === undefined) { console.log('array[2] is undefined'); } // true
+
+var array = ['first', 'second', undefined, 'fourth'];
+
+// returns ['first', 'second', undefined, 'fourth'];
+array.forEach(function(element) {
+ console.log(element);
+})</pre>
+
+<p>一旦 JavaScript 元素被保存为标准的对象属性,通过<code><a href="/en-US/docs/Web/JavaScript/Reference/Statements/for...in">for...in</a></code> 循环来迭代数组将变得不明智,因为正常元素和所有可枚举的属性都会被列出。</p>
+
+<h3 id="数组的方法array_methods">数组的方法(array methods)</h3>
+
+<p>{{jsxref("Array")}} 对象具有下列方法:</p>
+
+<p>{{jsxref("Array.concat", "concat()")}} 连接两个数组并返回一个新的数组。</p>
+
+<pre class="brush: js notranslate">var myArray = new Array("1", "2", "3");
+myArray = myArray.concat("a", "b", "c");
+// myArray is now ["1", "2", "3", "a", "b", "c"]
+</pre>
+
+<p>{{jsxref("Array.join", "join(deliminator = ',')")}} 将数组的所有元素连接成一个字符串。</p>
+
+<pre class="brush: js notranslate">var myArray = new Array("Wind", "Rain", "Fire");
+var list = myArray.join(" - "); // list is "Wind - Rain - Fire"
+</pre>
+
+<p>{{jsxref("Array.push", "push()")}} 在数组末尾添加一个或多个元素,并返回数组操作后的长度。</p>
+
+<pre class="brush: js notranslate">var myArray = new Array("1", "2");
+myArray.push("3"); // myArray is now ["1", "2", "3"]
+</pre>
+
+<p>{{jsxref("Array.pop", "pop()")}} 从数组移出最后一个元素,并返回该元素。</p>
+
+<pre class="brush: js notranslate">var myArray = new Array("1", "2", "3");
+var last = myArray.pop();
+// myArray is now ["1", "2"], last = "3"
+</pre>
+
+<p>{{jsxref("Array.shift", "shift()")}} 从数组移出第一个元素,并返回该元素。</p>
+
+<pre class="brush: js notranslate">var myArray = new Array ("1", "2", "3");
+var first = myArray.shift();
+// myArray is now ["2", "3"], first is "1"
+</pre>
+
+<p>{{jsxref("Array.shift", "unshift()")}} 在数组开头添加一个或多个元素,并返回数组的新长度。</p>
+
+<pre class="brush: js notranslate">var myArray = new Array ("1", "2", "3");
+myArray.unshift("4", "5");
+// myArray becomes ["4", "5", "1", "2", "3"]</pre>
+
+<p>{{jsxref("Array.slice", "slice(start_index, upto_index)")}} 从数组提取一个片段,并作为一个新数组返回。</p>
+
+<pre class="brush: js notranslate">var myArray = new Array ("a", "b", "c", "d", "e");
+myArray = myArray.slice(1, 4); // 包含索引1,不包括索引4
+ // returning [ "b", "c", "d"]
+</pre>
+
+<p>{{jsxref("Array.splice", "splice(index, count_to_remove, addElement1, addElement2, ...)")}}从数组移出一些元素,(可选)并替换它们。</p>
+
+<pre class="brush: js notranslate">var myArray = new Array ("1", "2", "3", "4", "5");
+myArray.splice(1, 3, "a", "b", "c", "d");
+// myArray is now ["1", "a", "b", "c", "d", "5"]
+// This code started at index one (or where the "2" was),
+// removed 3 elements there, and then inserted all consecutive
+// elements in its place.
+</pre>
+
+<p>{{jsxref("Array.reverse", "reverse()")}} 颠倒数组元素的顺序:第一个变成最后一个,最后一个变成第一个。</p>
+
+<pre class="brush: js notranslate">var myArray = new Array ("1", "2", "3");
+myArray.reverse();
+// transposes the array so that myArray = [ "3", "2", "1" ]
+</pre>
+
+<p>{{jsxref("Array.sort", "sort()")}} 给数组元素排序。</p>
+
+<pre class="brush: js notranslate">var myArray = new Array("Wind", "Rain", "Fire");
+myArray.sort();
+// sorts the array so that myArray = [ "Fire", "Rain", "Wind" ]
+</pre>
+
+<p><code>sort()</code> 也可以带一个回调函数来决定怎么比较数组元素。这个回调函数比较两个值,并返回3个值中的一个:</p>
+
+<p>例如,下面的代码通过字符串的最后一个字母进行排序:</p>
+
+<pre class="brush: js notranslate">var sortFn = function(a, b){
+ if (a[a.length - 1] &lt; b[b.length - 1]) return -1;
+ if (a[a.length - 1] &gt; b[b.length - 1]) return 1;
+ if (a[a.length - 1] == b[b.length - 1]) return 0;
+}
+myArray.sort(sortFn);
+// sorts the array so that myArray = ["Wind","Fire","Rain"]</pre>
+
+<ul>
+ <li>如果 a 小于 b ,返回 -1(或任何负数)</li>
+ <li>如果 <code>a</code> 大于 <code>b</code> ,返回 1 (或任何正数)</li>
+ <li>如果 <code>a</code> 和 <code>b</code> 相等,返回 0。</li>
+</ul>
+
+<p>{{jsxref("Array.indexOf", "indexOf(searchElement[, fromIndex])")}} 在数组中搜索<code>searchElement</code> 并返回第一个匹配的索引。</p>
+
+<pre class="brush: js notranslate">var a = ['a', 'b', 'a', 'b', 'a'];
+console.log(a.indexOf('b')); // logs 1
+// Now try again, starting from after the last match
+console.log(a.indexOf('b', 2)); // logs 3
+console.log(a.indexOf('z')); // logs -1, because 'z' was not found
+</pre>
+
+<p>{{jsxref("Array.lastIndexOf", "lastIndexOf(searchElement[, fromIndex])")}} 和 <code>indexOf 差不多,但这是从结尾开始,并且是反向搜索。</code></p>
+
+<pre class="brush: js notranslate">var a = ['a', 'b', 'c', 'd', 'a', 'b'];
+console.log(a.lastIndexOf('b')); // logs 5
+// Now try again, starting from before the last match
+console.log(a.lastIndexOf('b', 4)); // logs 1
+console.log(a.lastIndexOf('z')); // logs -1
+</pre>
+
+<p>{{jsxref("Array.forEach", "forEach(callback[, thisObject])")}} 在数组每个元素项上执行<code>callback</code>。</p>
+
+<pre class="brush: js notranslate">var a = ['a', 'b', 'c'];
+a.forEach(function(element) { console.log(element);} );
+// logs each item in turn
+</pre>
+
+<p>{{jsxref("Array.map", "map(callback[, thisObject])")}} 在数组的每个单元项上执行callback函数,并把返回包含回调函数返回值的新数组(译者注:也就是遍历数组,并通过callback对数组元素进行操作,并将所有操作结果放入数组中并返回该数组)。</p>
+
+<pre class="brush: js notranslate">var a1 = ['a', 'b', 'c'];
+var a2 = a1.map(function(item) { return item.toUpperCase(); });
+console.log(a2); // logs A,B,C
+</pre>
+
+<p>{{jsxref("Array.filter", "filter(callback[, thisObject])")}} 返回一个包含所有在回调函数上返回为true的元素的新数组(译者注:callback在这里担任的是过滤器的角色,当元素符合条件,过滤器就返回true,而filter则会返回所有符合过滤条件的元素)。</p>
+
+<pre class="brush: js notranslate">var a1 = ['a', 10, 'b', 20, 'c', 30];
+var a2 = a1.filter(function(item) { return typeof item == 'number'; });
+console.log(a2); // logs 10,20,30
+</pre>
+
+<p>{{jsxref("Array.every", "every(callback[, thisObject])")}} 当数组中每一个元素在callback上被返回true时就返回true(译者注:同上,every其实类似filter,只不过它的功能是判断是不是数组中的所有元素都符合条件,并且返回的是布尔值)。</p>
+
+<pre class="brush: js notranslate">function isNumber(value){
+ return typeof value == 'number';
+}
+var a1 = [1, 2, 3];
+console.log(a1.every(isNumber)); // logs true
+var a2 = [1, '2', 3];
+console.log(a2.every(isNumber)); // logs false
+</pre>
+
+<p>{{jsxref("Array.some", "some(callback[, thisObject])")}} 只要数组中有一项在callback上被返回true,就返回true(译者注:同上,类似every,不过前者要求都符合筛选条件才返回true,后者只要有符合条件的就返回true)。</p>
+
+<pre class="brush: js notranslate">function isNumber(value){
+ return typeof value == 'number';
+}
+var a1 = [1, 2, 3];
+console.log(a1.some(isNumber)); // logs true
+var a2 = [1, '2', 3];
+console.log(a2.some(isNumber)); // logs true
+var a3 = ['1', '2', '3'];
+console.log(a3.some(isNumber)); // logs false
+</pre>
+
+<p>以上方法都带一个被称为迭代方法的的回调函数,因为他们以某种方式迭代整个数组。都有一个可选的第二参数 <code>thisObject</code>,如果提供了这个参数,<code>thisObject</code> 变成回调函数内部的 this 关键字的值。如果没有提供,例如函数在一个显示的对象上下文外被调用时,this 将引用全局对象({{domxref("window")}}).</p>
+
+<p>实际上在调用回调函数时传入了3个参数。第一个是当前元素项的值,第二个是它在数组中的索引,第三个是数组本身的一个引用。 JavaScript 函数忽略任何没有在参数列表中命名的参数,因此提供一个只有一个参数的回调函数是安全的,例如 <code>alert</code> 。</p>
+
+<p>{{jsxref("Array.reduce", "reduce(callback[, initialValue])")}} 使用回调函数 <code>callback(firstValue, secondValue)</code> 把数组列表计算成一个单一值(译者注:他数组元素两两递归处理的方式把数组计算成一个值)</p>
+
+<pre class="brush: js notranslate">var a = [10, 20, 30];
+var total = a.reduce(function(first, second) { return first + second; }, 0);
+console.log(total) // Prints 60
+</pre>
+
+<p>{{jsxref("Array.reduceRight", "reduceRight(callback[, initalvalue])")}} 和 <code>reduce()相似,但这从最后一个元素开始的。</code></p>
+
+<p><code>reduce</code> 和 <code>reduceRight</code> 是迭代数组方法中最不被人熟知的两个函数.。他们应该使用在那些需要把数组的元素两两递归处理,并最终计算成一个单一结果的算法。</p>
+
+<h3 id="多维数组multi-dimensional_arrays">多维数组(multi-dimensional arrays)</h3>
+
+<p>数组是可以嵌套的, 这就意味着一个数组可以作为一个元素被包含在另外一个数组里面。利用JavaScript数组的这个特性, 可以创建多维数组。</p>
+
+<p>以下代码创建了一个二维数组。</p>
+
+<pre class="brush: js notranslate">var a = new Array(4);
+for (i = 0; i &lt; 4; i++) {
+ a[i] = new Array(4);
+ for (j = 0; j &lt; 4; j++) {
+ a[i][j] = "[" + i + "," + j + "]";
+ }
+}
+</pre>
+
+<p>这个例子创建的数组拥有以下行数据:</p>
+
+<pre class="notranslate">Row 0: [0,0] [0,1] [0,2] [0,3]
+Row 1: [1,0] [1,1] [1,2] [1,3]
+Row 2: [2,0] [2,1] [2,2] [2,3]
+Row 3: [3,0] [3,1] [3,2] [3,3]
+</pre>
+
+<h3 id="数组和正则表达式">数组和正则表达式</h3>
+
+<p>当一个数组作为字符串和正则表达式的匹配结果时,该数组将会返回相关匹配信息的属性和元素。 <a href="/en-US/docs/JavaScript/Reference/Global_Objects/RegExp/exec" title="en-US/docs/JavaScript/Reference/Global Objects/RegExp/exec"><code>RegExp.exec()</code></a>, <code><a href="/en-US/docs/JavaScript/Reference/Global_Objects/String/match" title="en-US/docs/JavaScript/Reference/Global Objects/String/match">String.match()</a> 和</code> <code><a href="/en-US/docs/JavaScript/Reference/Global_Objects/String/split" title="en-US/docs/JavaScript/Reference/Global
+Objects/String/split">String.split()</a> 的返回值是一个数组。</code> 使用数组和正则表达式的的更多信息, 请看 <a href="/en-US/docs/Web/JavaScript/Guide/Regular_Expressions" title="en-US/docs/JavaScript/Guide/Regular Expressions">Regular Expressions</a>.</p>
+
+<h3 id="使用类数组对象array-like_objects">使用类数组对象(array-like objects)</h3>
+
+<p>一些 JavaScript 对象, 例如 {{domxref("document.getElementsByTagName()")}} 返回的 {{domxref("NodeList")}} 或者函数内部可用的 <a href="/en-US/docs/Web/JavaScript/Reference/Functions/arguments" title="en-US/docs/JavaScript/Reference/Functions andfunctionscope/arguments"><code>arguments</code></a> 对象,他们表面上看起来,外观和行为像数组,但是不共享他们所有的方法。例如 <code>arguments</code> 对象就提供一个 <code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/length">length</a></code> 属性,但是不实现 {{jsxref("Array.forEach", "forEach()")}} 方法。</p>
+
+<p>Array的原生(prototype)方法可以用来处理类似数组行为的对象,例如: :</p>
+
+<pre class="brush: js notranslate">function printArguments() {
+  Array.prototype.forEach.call(arguments, function(item) {
+ console.log(item);
+ });
+}</pre>
+
+<p>Array的常规方法也可以用于处理字符串,因为它提供了序列访问字符转为数组的简单方法:</p>
+
+<pre class="brush: js notranslate">Array.prototype.forEach.call("a string", function(chr) {
+ console.log(chr);
+});</pre>
+
+<h2 id="数组推导式(Array_comprehensions)">数组推导式(Array comprehensions)</h2>
+
+<p>在<a href="/en-US/docs/Web/JavaScript/New_in_JavaScript/1.7">JavaScript 1.7</a> 被介绍并计划在 <a href="/en-US/docs/Web/JavaScript/New_in_JavaScript/ECMAScript_7_support_in_Mozilla">ECMAScript 7</a>, <a href="/en-US/docs/Web/JavaScript/Reference/Operators/Array_comprehensions">array comprehensions</a> 被规范化并提供一个有用的快捷方式,用来实现如何在另一个数组的基础上构造一个新的数组。推导式可以经常被用在那些需要调用 <code>map()</code> 和 <code>filter()函数的地方,</code>或作为一种结合这两种方式。</p>
+
+<p>下面的推导式创建一个数字数组并且创建一个新的数组,数组的每个元素都是原来数值的两倍(译者注:这种形式类似于Python的列表推导式)。</p>
+
+<pre class="brush: js notranslate">var numbers = [1, 2, 3, 4];
+var doubled = [for (i of numbers) i * 2];
+console.log(doubled); // logs 2,4,6,8
+</pre>
+
+<p>这跟下面的map()方法的操作是等价的。</p>
+
+<pre class="brush: js notranslate">var doubled = numbers.map(function(i){return i * 2;});
+</pre>
+
+<p>推导式也可以用来筛选满足条件表达式的元素. 下面的推导式用来筛选是2的倍数的元素:</p>
+
+<pre class="brush: js notranslate">var numbers = [1, 2, 3, 21, 22, 30];
+var evens = [i for (i of numbers) if (i % 2 === 0)];
+console.log(evens); // logs 2,22,30
+</pre>
+
+<p><code>filter()</code> 也可以达到相同的目的:</p>
+
+<pre class="brush: js notranslate">var evens = numbers.filter(function(i){return i % 2 === 0;});
+</pre>
+
+<p><code>map()</code> <code>和filter()</code> 类型的操作可以被组合(等效)为单个数组推导式。这里就有一个过滤出偶数,创建一个它的倍数数组的例子:</p>
+
+<pre class="brush: js notranslate">var numbers = [1, 2, 3, 21, 22, 30];
+var doubledEvens = [i * 2 for (i of numbers) if (i % 2 === 0)];
+console.log(doubledEvens); // logs 4,44,60
+</pre>
+
+<p>数组推导式隐含了块作用域。新的变量(如例子中的i)类似于是采用 <a href="/en-US/docs/Web/JavaScript/Reference/Statements/let" title="/en-US/docs/JavaScript/Reference/Statements/let"><code>let</code></a>声明的。这意味着他们不能在推导式以外访问。</p>
+
+<p>数组推导式的输入不一定必须是数组; <a href="/en-US/docs/Web/JavaScript/Guide/Iterators_and_Generators" title="en-US/docs/JavaScript/Guide/Iterators and Generators">迭代器和生成器</a> 也是可以的。</p>
+
+<p>甚至字符串也可以用来作为输入; 实现filter或者map行为 (参考上面类似数组行为的对象)如下:</p>
+
+<pre class="brush: js notranslate">var str = 'abcdef';
+var consonantsOnlyStr = [c for (c of str) if (!(/[aeiouAEIOU]/).test(c)) ].join(''); // 'bcdf'
+var interpolatedZeros = [c+'0' for (c of str) ].join(''); // 'a0b0c0d0e0f0'
+</pre>
+
+<p>不过,输入形式是不能保存的,所以我们要使用join()回复到一个字符串。</p>
+
+<h2 id="类型化数组Typed_Arrays">类型化数组(Typed Arrays )</h2>
+
+<p><a href="/en-US/docs/Web/JavaScript/Typed_arrays">JavaScript typed arrays</a> 是类数组对象(array-like object),其提供访问原始二进制数据的机制。 就像你知道的那样, {{jsxref("Array")}} 对象动态增长和收缩,可以有任何JavaScript值。但对于类型化数组,JavaScript引擎执行优化使得这些数组访问速度快速。 随着Web应用程序变得越来越强大,添加音频和视频处理等功能、可以使用 <a href="/en-US/docs/WebSockets">WebSockets</a> 、使用原始数据, 这都需要访问原始的二进制数据,所以专门的优化将有助于JavaScript代码能够快速和容易地操纵原始二进制数据类型的数组。</p>
+
+<h3 id="缓冲区和视图:类型化的数组结构">缓冲区和视图:类型化的数组结构</h3>
+
+<p>为了实现最大的灵活性和效率,JavaScript类型数组被分解为缓冲(Buffer)和视图(views)。缓冲(由{{jsxref("ArrayBuffer")}} 实现)是代表数据块的对象,它没有格式可言,并没有提供任何机制来访问其内容。为了访问包含在缓冲区中的内存,您需要使用视图。视图提供了一个上下文,即数据类型、起始偏移量和元素数,这些元素将数据转换为实际类型数组。</p>
+
+<p><img alt="Typed arrays in an ArrayBuffer" src="https://mdn.mozillademos.org/files/8629/typed_arrays.png" style="height: 278px; width: 666px;"></p>
+
+<h3 id="ArrayBuffer">ArrayBuffer</h3>
+
+<p> {{jsxref("ArrayBuffer")}}是一种数据类型,用于表示一个通用的、固定长度的二进制数据缓冲区。你不能直接操纵一个ArrayBuffer中的内容;你需要创建一个数组类型视图或{{jsxref("DataView")}}来代表特定格式的缓冲区,并从而实现读写缓冲区的内容。</p>
+
+<h3 id="类型数组视图Typed_array_views">类型数组视图(Typed array views)</h3>
+
+<p>类型数组视图具有自描述性的名字,并且提供数据类型信息,例如<code>Int8</code>, <code>Uint32</code>, <code>Float64等等。</code>如一个特定类型数组视图<code>Uint8ClampedArray</code>. 它意味着数据元素只包含0到255的整数值。它通常用于<a href="/en-US/docs/Web/API/ImageData">Canvas数据处理</a>,例如.</p>
+
+<p>{{page("/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray", "TypedArray_objects")}}</p>
+
+<p>更多信息参考 <a href="/en-US/docs/Web/JavaScript/Typed_arrays">JavaScript typed arrays</a> 与参考文档中 {{jsxref("TypedArray")}}对象的不同</p>
+
+<p>{{PreviousNext("Web/JavaScript/Guide/Regular_Expressions", "Web/JavaScript/Guide/Keyed_Collections")}}</p>
diff --git a/files/zh-cn/web/javascript/guide/introduction/index.html b/files/zh-cn/web/javascript/guide/introduction/index.html
new file mode 100644
index 0000000000..8a6a283d5c
--- /dev/null
+++ b/files/zh-cn/web/javascript/guide/introduction/index.html
@@ -0,0 +1,147 @@
+---
+title: 介绍
+slug: Web/JavaScript/Guide/Introduction
+tags:
+ - JavaScript
+ - 指南
+translation_of: Web/JavaScript/Guide/Introduction
+---
+<div>{{jsSidebar("JavaScript 指南")}} {{PreviousNext("Web/JavaScript/Guide", "Web/JavaScript/Guide/Grammar_and_types")}}</div>
+
+<div class="summary">
+<p>本章节介绍了 JavaScript,并且讨论了它的一些基本概念。</p>
+</div>
+
+<h2 id="你应该已经掌握哪些知识?">你应该已经掌握哪些知识?</h2>
+
+<p>我们假设你已经掌握了以下基础技能:</p>
+
+<ul>
+ <li>对互联网和万维网({{Glossary("WWW")}})有基本的认识。</li>
+ <li>熟悉超文本标记语言({{Glossary("HTML")}})。</li>
+ <li>一些编程经验。如果您初识编程,请先试着看看主页列出的有关 <a href="/zh-CN/docs/Web/JavaScript" title="/en-US/docs/">JavaScript</a> 的教程。</li>
+</ul>
+
+<h2 id="去哪里获取有关_JavaScript_的信息?">去哪里获取有关 JavaScript 的信息?</h2>
+
+<p>MDN 上的 JavaScript 文档包括以下内容:</p>
+
+<ul>
+ <li><a href="/zh-CN/Learn">认识 Web</a> 为初学者提供信息,并介绍一些关于编程和互联网的基本概念。</li>
+ <li><a href="/zh-CN/docs/Web/JavaScript/Guide" title="en/Core_JavaScript_1.5_Guide">JavaScript 入门</a> (即本教程)提供 JavaScript 这门语言及其目标的概述。</li>
+ <li><a href="/zh-CN/docs/Web/JavaScript/Reference" title="en/JavaScript/Reference">JavaScript 参考</a> 提供关于 JavaScript 的详细参考资料。</li>
+</ul>
+
+<p>如果你刚开始学习 JavaScript,请详细阅读 <a href="/zh-CN/Learn">学习区(Learning area)</a> 和 <a href="/zh-CN/docs/Web/JavaScript/Guide" title="en/Core_JavaScript_1.5_Guide">JavaScript 入门</a> 的文章。如果你已经掌握了 JavaScript 基础知识, 你可以通过 <a href="/zh-CN/docs/Web/JavaScript/Reference" title="en/JavaScript/Reference">JavaScript 参考</a> 来了解更多关于单个(individual)对象和语句的细节。</p>
+
+<h2 id="什么是_JavaScript">什么是 JavaScript?</h2>
+
+<p>JavaScript 是一门跨平台、面向对象的脚本语言,它能使网页可交互(例如拥有复杂的动画,可点击的按钮,通俗的菜单等)。另外还有高级的服务端Javascript版本,例如Node.js,它可以让你在网页上添加更多功能,不仅仅是下载文件(例如在多台电脑之间的协同合作)。在宿主环境(例如 web 浏览器)中, JavaScript 能够通过其所连接的环境提供的编程接口进行控制。</p>
+
+<p>JavaScript 内置了一些对象的标准库,比如数组(<code>Array</code>),日期(<code>Date</code>),数学(<code>Math</code>)和一套核心语句,包括运算符、流程控制符以及声明方式等。JavaScript 的核心部分可以通过添加对象来扩展语言以适应不同用途;例如:</p>
+
+<ul>
+ <li>客户端的 JavaScript 通过提供对象,控制浏览器及其文档对象模型(DOM),来扩展语言核心。例如:客户端的拓展代码允许应用程序将元素放在某个 HTML 表单中,并且支持响应用户事件,比如鼠标点击、表单提交和页面导航。</li>
+ <li><em> </em>服务端的 JavaScript 则通过提供有关在服务器上运行 JavaScript 的对象来可扩展语言核心。例如:服务端版本直接支持应用和数据库通信,提供应用不同调用间的信息连续性,或者在服务器上执行文件操作。</li>
+</ul>
+
+<p>这意味着,在浏览器中,JavaScript 可以改变网页(DOM)的外观与样式。同样地,在服务器上,Node.js 中的 JavaScript 可以对浏览器上编写的代码发出的客户端请求做出响应。</p>
+
+<h2 id="JavaScript_and_Java" name="JavaScript_and_Java">JavaScript 和 Java</h2>
+
+<p>JavaScript 和 Java 有一些共性但是在另一些方面有着根本性区别。JavaScript语言类似 Java 但是并没有 Java 的静态类型和强类型检查特性。JavaScript 遵循了 Java 的表达式语法,命名规范以及基础流程控制,这也是 JavaScript 从 LiveScript 更名的原因。</p>
+
+<p>与 Java 通过声明的方式构建类的编译时系统不同,JavaScript 采用基于少量的数据类型如数字、布尔、字符串值的运行时系统。JavaScript 拥有基于原型的对象模型提供的动态继承;也就是说,独立对象的继承是可以改变的。 JavaScript 支持匿名函数。 函数也可以作为对象的属性被当做宽松的类型方式执行。</p>
+
+<p>与 Java 相比,Javascript 是一门形式自由的语言。你不必声明所有的变量,类和方法。你不必关心方法是否是公有、私有或者受保护的,也不需要实现接口。无需显式指定变量、参数、方法返回值的数据类型。</p>
+
+<p>Java 是基于类的编程语言,设计的初衷就是为了确保快速执行和类型安全。类型安全,举个例子,你不能将一个 Java 整数变量转化为一个对象引用,或者由Java字节码访问专有存储器。Java基于类的模型,意味着程序包含专有的类及其方法。Java的类继承和强类型要求紧耦合的对象层级结构。这些要求使得Java编程比JavaScript要复杂的多。</p>
+
+<p>相比之下,JavaScript 传承了 HyperTalk 和 dBASE 语句精简、动态类型等精髓,这些脚本语言为更多开发者提供了一种语法简单、内置功能强大以及用最小需求创建对象的编程工具。</p>
+
+<table class="standard-table">
+ <caption>JavaScript 和 Java 的对比</caption>
+ <thead>
+ <tr>
+ <th scope="col">JavaScript</th>
+ <th scope="col">Java</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>面向对象。不区分对象类型。通过原型机制继承,任何对象的属性和方法均可以被动态添加。</td>
+ <td>基于类系统。分为类和实例,通过类层级的定义实现继承。不能动态增加对象或类的属性或方法。</td>
+ </tr>
+ <tr>
+ <td>变量类型不需要提前声明(动态类型)。</td>
+ <td>变量类型必须提前声明(静态类型)。</td>
+ </tr>
+ <tr>
+ <td>不能直接自动写入硬盘。</td>
+ <td>可以直接自动写入硬盘。</td>
+ </tr>
+ </tbody>
+</table>
+
+<p>请查看章节 <a href="/zh-CN/docs/Web/JavaScript/Guide/Details_of_the_Object_Model">对象模型的详情</a> 来了解更多JavaScript和Java的不同。</p>
+
+<h2 id="JavaScript_and_the_ECMAScript_Specification" name="JavaScript_and_the_ECMAScript_Specification">JavaScript 和 ECMAScript 规范</h2>
+
+<p>JavaScript 的标准化组织是 <a class="external" href="http://www.ecma-international.org/">ECMA</a> ——这个欧洲信息与通信系统标准化协会提供基于 Javascript 的标准化方案(ECMA 原先是欧洲计算机制造商协会的首字母缩写)。这种标准化版本的 JavaScript 被称作 ECMAScript,在所有支持该标准的应用中以相同的方式工作。公司可以使用开放标准语言来开发他们自己的 JavaScript 实现版本。ECMAScript 标准在ECMA-262规范中进行文档化。 参照 <a href="/en-US/docs/Web/JavaScript/New_in_JavaScript">JavaScript的新特性</a> 以便学习更多关于不同版本的 JavaScript 和 ECMAScript 规范版本。</p>
+
+<p>ECMA-262 标准也通过了 国际标准化组织(<a class="external" href="http://www.iso.ch/">ISO</a>)的 ISO-16262。你可以<a href="http://www.ecma-international.org/publications/standards/Ecma-262.htm">在这里</a>找到该规范文件。 ECMAScript 规范并没有描述文档对象模型(<a href="/zh-CN/docs/Web/API/Document_Object_Model">DOM</a>),该模型由 万维网联盟(<a href="http://www.w3.org/">W3C</a>) 制定。DOM 定义了HTML文件对象被脚本操作的方法。为了更清楚地了解当使用JavaScript编程时用到的不同技术,请参阅 <a href="/zh-CN/docs/Web/JavaScript/JavaScript_technologies_overview">JavaScript 技术概述</a>。</p>
+
+<h3 id="JavaScript_Documentation_versus_the_ECMAScript_Specification" name="JavaScript_Documentation_versus_the_ECMAScript_Specification">JavaScript 文献 和 ECMAScript 规范</h3>
+
+<p>ECMAScript规范是实现ECMAScript的一组需求;如果您想在ECMAScript实现或引擎(如Firefox中的SpiderMonkey或Chrome中的V8)中实现符合标准的语言特性,那么它是非常有用的。</p>
+
+<p>ECMAScript文档不是用来帮助脚本程序员的;使用JavaScript文档获取关于编写脚本的信息。</p>
+
+<p>ECMAScript规范使用了JavaScript程序员可能不熟悉的术语和语法。尽管ECMAScript中对语言的描述可能有所不同,但语言本身保持不变。JavaScript支持ECMAScript规范中列出的所有功能。</p>
+
+<p>JavaScript文档描述了适合JavaScript程序员的语言方面。</p>
+
+<h2 id="JavaScript_入门">JavaScript 入门</h2>
+
+<p>开始使用 JavaScript 很容易,你只需要一个现代 Web 浏览器。这篇教程包含了一些只在最新版本的火狐浏览器上才有的功能,所以建议大家使用最新版本的火狐浏览器。</p>
+
+<p>火狐内置了两款非常棒的工具用来实验 JavaScript:浏览器控制台和代码草稿纸。</p>
+
+<h3 id="Web_控制台(Web_Console)">Web 控制台(Web Console)</h3>
+
+<p><a href="/zh-CN/docs//Tools/Web_Console">Web 控制台</a> 不仅可以展示当前已加载页面的信息,还包含一个可以在当前页面执行Javascript表达式的 <a href="/zh-CN/docs/Tools/Web_Console#The_command_line_interpreter">命令行。</a></p>
+
+<p>在火狐浏览器菜单栏的 “工具" =&gt; "Web开发者" =&gt; "Web控制台" 可以打开控制台( 在Windows和Linux上<kbd>Ctrl</kbd>+<kbd>Shift</kbd>+<kbd>K</kbd> ,Mac上<kbd>Cmd</kbd>+<kbd>Option</kbd>+<kbd>K</kbd>) ,它会如期出现在浏览器窗口的底部。如图,最下一行就是可以执行输入的命令行,面板上可以显示执行结果:</p>
+
+<p><img alt="" src="https://mdn.mozillademos.org/files/7363/web-console-commandline.png" style="display: block; margin-left: auto; margin-right: auto;"></p>
+
+<p>控制台的工作方式与eval完全相同:返回最后输入的表达式。为了简单起见,可以想象每次输入到控制台的东西实际上都被 console.log 所包围。</p>
+
+<pre class="notranslate">function greetMe(yourName) { alert('Hello ' + yourName); } <code>console.log(eval('3 + 5'));</code></pre>
+
+<h3 id="代码草稿纸(Scratchpad)">代码草稿纸(Scratchpad)</h3>
+
+<p>Web控制台 对于执行单行 JS 命令十分便捷,虽然你也可以执行多行命令,但是在控制台操作并不方便。除此之外,使用控制台你无法保存你的代码片段。因此对于更为复杂的代码片段,<a href="/zh-CN/docs/Tools/Scratchpad">Scratchpad(代码草稿纸)</a> 是一个更好的工具。</p>
+
+<p>从 “Web开发者” 菜单(在火狐浏览器的主菜单下)中选择 “代码草稿纸” 来打开(<kbd>Shift</kbd>+<kbd>F4</kbd>)。它是一个拥有独立窗口的编辑器,你可以用来编辑和在浏览器中执行 JavaScript。你也可以将代码保存到本地磁盘,或者从本地载入。</p>
+
+<p>如果你选择显示,草稿纸中的代码会在浏览器中执行,并在内容后面以注释的形式插入返回的结果:</p>
+
+<p><img alt="" src="https://mdn.mozillademos.org/files/7365/scratchpad.png" style="display: block; margin-left: auto; margin-right: auto;"></p>
+
+<h3 id="Hello_world">Hello world</h3>
+
+<p>学习JavaScript 的第一步,打开浏览器的代码草稿纸尝试编写你的第一个 JavaScript 版本的 “Hello world” 程序。</p>
+
+<pre class="brush: js notranslate">function greetMe(user) {
+ alert('Hi ' + user);
+}
+
+greetMe('Alice'); // 'Hi Alice'
+</pre>
+
+<p>在 Scratchpad(代码草稿纸)中选择要执行的代码,然后点击“运行(Ctrl+R)”就可以在浏览器中看到选中代码的执行结果。</p>
+
+<p>在接下来的章节里,该指南将介绍 JavaScript 的语法以及语言特性,届时你将可以使用它编写更加复杂的程序。</p>
+
+<p>{{PreviousNext("Web/JavaScript/Guide", "Web/JavaScript/Guide/Grammar_and_types")}}</p>
diff --git a/files/zh-cn/web/javascript/guide/iterators_and_generators/index.html b/files/zh-cn/web/javascript/guide/iterators_and_generators/index.html
new file mode 100644
index 0000000000..07533c60c2
--- /dev/null
+++ b/files/zh-cn/web/javascript/guide/iterators_and_generators/index.html
@@ -0,0 +1,200 @@
+---
+title: 迭代器和生成器
+slug: Web/JavaScript/Guide/Iterators_and_Generators
+tags:
+ - Generator
+ - Guide
+ - Intermediate
+ - Iterator
+ - JavaScript
+ - 中级
+ - 生成器
+ - 迭代器
+translation_of: Web/JavaScript/Guide/Iterators_and_Generators
+---
+<div>{{jsSidebar("JavaScript Guide")}} {{PreviousNext("Web/JavaScript/Guide/Using_promises", "Web/JavaScript/Guide/Meta_programming")}}</div>
+
+<p class="summary">处理集合中的每个项是很常见的操作。JavaScript 提供了许多迭代集合的方法,从简单的 {{jsxref("Statements/for","for")}} 循环到 {{jsxref("Global_Objects/Array/map","map()")}} 和 {{jsxref("Global_Objects/Array/filter","filter()")}}。迭代器和生成器将迭代的概念直接带入核心语言,并提供了一种机制来自定义 {{jsxref("Statements/for...of","for...of")}} 循环的行为。</p>
+
+<p>若想了解更多详情,请参考:</p>
+
+<ul>
+ <li><a href="/zh-CN/docs/Web/JavaScript/Reference/Iteration_protocols">迭代协议</a></li>
+ <li>{{jsxref("Statements/for...of","for...of")}}</li>
+ <li>{{jsxref("Statements/function*","function*")}} 和 {{jsxref("Generator")}}</li>
+ <li>{{jsxref("Operators/yield","yield")}} 和 {{jsxref("Operators/yield*","yield*")}}</li>
+</ul>
+
+<h2 id="迭代器">迭代器</h2>
+
+<p>在 JavaScript 中,<strong>迭代器</strong>是一个对象,它定义一个序列,并在终止时可能返回一个返回值。 更具体地说,迭代器是通过使用 <code>next()</code> 方法实现 <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols#The_iterator_protocol">Iterator protocol</a> 的任何一个对象,该方法返回具有两个属性的对象: <code>value</code>,这是序列中的 next 值;和 <code>done</code> ,如果已经迭代到序列中的最后一个值,则它为 <code>true</code> 。如果 <code>value</code> 和 <code>done</code> 一起存在,则它是迭代器的返回值。</p>
+
+<p>一旦创建,迭代器对象可以通过重复调用next()显式地迭代。 迭代一个迭代器被称为消耗了这个迭代器,因为它通常只能执行一次。 在产生终止值之后,对next()的额外调用应该继续返回{done:true}。<br>
+ <br>
+ Javascript中最常见的迭代器是Array迭代器,它只是按顺序返回关联数组中的每个值。 虽然很容易想象所有迭代器都可以表示为数组,但事实并非如此。 数组必须完整分配,但迭代器仅在必要时使用,因此可以表示无限大小的序列,例如0和无穷大之间的整数范围。</p>
+
+<p><br>
+ 这是一个可以做到这一点的例子。 它允许创建一个简单的范围迭代器,它定义了从开始(包括)到结束(独占)间隔步长的整数序列。 它的最终返回值是它创建的序列的大小,由变量iterationCount跟踪。</p>
+
+<pre class="brush: js">function makeRangeIterator(start = 0, end = Infinity, step = 1) {
+ let nextIndex = start;
+ let iterationCount = 0;
+
+ const rangeIterator = {
+ next: function() {
+ let result;
+ if (nextIndex &lt; end) {
+ result = { value: nextIndex, done: false }
+ nextIndex += step;
+ iterationCount++;
+ return result;
+ }
+ return { value: iterationCount, done: true }
+ }
+ };
+ return rangeIterator;
+}</pre>
+
+<p>使用这个迭代器看起来像这样:</p>
+
+<pre class="brush: js">let it = makeRangeIterator(1, 10, 2);
+
+let result = it.next();
+while (!result.done) {
+ console.log(result.value); // 1 3 5 7 9
+ result = it.next();
+}
+
+console.log("Iterated over sequence of size: ", result.value); // 5
+
+</pre>
+
+<div class="note">
+<p>反射性地知道特定对象是否是迭代器是不可能的。 如果您需要这样做,请使用 <a href="#Iterables">Iterables</a>.</p>
+</div>
+
+<h2 id="生成器函数">生成器函数</h2>
+
+<p>虽然自定义的迭代器是一个有用的工具,但由于需要显式地维护其内部状态,因此需要谨慎地创建。生成器函数提供了一个强大的选择:它允许你定义一个包含自有迭代算法的函数, 同时它可以自动维护自己的状态。 生成器函数使用 {{jsxref("Statements/function*","function*")}}语法编写。 最初调用时,生成器函数不执行任何代码,而是返回一种称为Generator的迭代器。 通过调用生成器的下一个方法消耗值时,Generator函数将执行,直到遇到yield关键字。</p>
+
+<p>可以根据需要多次调用该函数,并且每次都返回一个新的Generator,但每个Generator只能迭代一次。</p>
+
+<p>我们现在可以调整上面的例子了。 此代码的行为是相同的,但实现更容易编写和读取。</p>
+
+<pre class="brush: js">function* makeRangeIterator(start = 0, end = Infinity, step = 1) {
+ for (let i = start; i &lt; end; i += step) {
+ yield i;
+ }
+}
+var a = makeRangeIterator(1,10,2)
+a.next() // {value: 1, done: false}
+a.next() // {value: 3, done: false}
+a.next() // {value: 5, done: false}
+a.next() // {value: 7, done: false}
+a.next() // {value: 9, done: false}
+a.next() // {value: undefined, done: true}
+</pre>
+
+<h2 id="可迭代对象">可迭代对象</h2>
+
+<p>若一个对象拥有迭代行为,比如在 {{jsxref("Statements/for...of", "for...of")}} 中会循环哪些值,那么那个对象便是一个可迭代对象。一些内置类型,如 {{jsxref("Array")}} 或 {{jsxref("Map")}} 拥有默认的迭代行为,而其他类型(比如{{jsxref("Object")}})则没有。</p>
+
+<p>为了实现<strong>可迭代</strong>,一个对象必须实现 <strong>@@iterator</strong> 方法,这意味着这个对象(或其<a href="/zh-CN/docs/Web/JavaScript/Guide/Inheritance_and_the_prototype_chain">原型链</a>中的任意一个对象)必须具有一个带 {{jsxref("Symbol.iterator")}} 键(key)的属性。</p>
+
+<p>可以多次迭代一个迭代器,或者只迭代一次。 程序员应该知道是哪种情况。 只能迭代一次的Iterables(例如Generators)通常从它们的<strong>@@iterator</strong>方法中返回它本身,其中那些可以多次迭代的方法必须在每次调用<strong>@@iterator</strong>时返回一个新的迭代器。</p>
+
+<h3 id="自定义的可迭代对象">自定义的可迭代对象</h3>
+
+<p>我们可以像这样实现自己的可迭代对象:</p>
+
+<pre class="brush: js">var myIterable = {
+ *[Symbol.iterator]() {
+ yield 1;
+ yield 2;
+ yield 3;
+ }
+}
+
+for (let value of myIterable) {
+ console.log(value);
+}
+// 1
+// 2
+// 3
+
+// 或者
+
+[...myIterable]; // [1, 2, 3]
+</pre>
+
+<h3 id="内置可迭代对象">内置可迭代对象</h3>
+
+<p>{{jsxref("String")}}、{{jsxref("Array")}}、{{jsxref("TypedArray")}}、{{jsxref("Map")}} 和 {{jsxref("Set")}} 都是内置可迭代对象,因为它们的原型对象都拥有一个 {{jsxref("Symbol.iterator")}} 方法。</p>
+
+<h3 id="用于可迭代对象的语法">用于可迭代对象的语法</h3>
+
+<p>一些语句和表达式专用于可迭代对象,例如 {{jsxref("Statements/for...of","for-of")}} 循环,{{jsxref("Operators/Spread_operator","展开语法")}},{{jsxref("Operators/yield*", "yield*")}} 和 {{jsxref("Operators/Destructuring_assignment", "解构赋值")}}。</p>
+
+<pre class="brush: js">for (let value of ['a', 'b', 'c']) {
+ console.log(value);
+}
+// "a"
+// "b"
+// "c"
+
+[...'abc']; // ["a", "b", "c"]
+
+function* gen() {
+ yield* ['a', 'b', 'c'];
+}
+
+gen().next(); // { value: "a", done: false }
+
+[a, b, c] = new Set(['a', 'b', 'c']);
+a; // "a"
+
+</pre>
+
+<h2 id="高级生成器">高级生成器</h2>
+
+<p>生成器会按需计算它们的产生值,这使得它们能够有效的表示一个计算成本很高的序列,甚至是如上所示的一个无限序列。</p>
+
+<p>The {{jsxref("Global_Objects/Generator/next","next()")}} 方法也接受一个参数用于修改生成器内部状态。传递给 <code>next()</code> 的参数值会被yield接收。要注意的是,传给第一个 <code>next()</code> 的值会被忽略。</p>
+
+<p>下面的是斐波那契数列生成器,它使用了 <code>next(x)</code> 来重新启动序列:</p>
+
+<pre class="brush: js">function* fibonacci() {
+ var fn1 = 0;
+ var fn2 = 1;
+ while (true) {
+ var current = fn1;
+ fn1 = fn2;
+ fn2 = current + fn1;
+ var reset = yield current;
+ if (reset) {
+ fn1 = 0;
+ fn2 = 1;
+ }
+ }
+}
+
+var sequence = fibonacci();
+console.log(sequence.next().value); // 0
+console.log(sequence.next().value); // 1
+console.log(sequence.next().value); // 1
+console.log(sequence.next().value); // 2
+console.log(sequence.next().value); // 3
+console.log(sequence.next().value); // 5
+console.log(sequence.next().value); // 8
+console.log(sequence.next(true).value); // 0
+console.log(sequence.next().value); // 1
+console.log(sequence.next().value); // 1
+console.log(sequence.next().value); // 2</pre>
+
+<p>你可以通过调用其 {{jsxref("Global_Objects/Generator/throw","throw()")}} 方法强制生成器抛出异常,并传递应该抛出的异常值。这个异常将从当前挂起的生成器的上下文中抛出,就好像当前挂起的 <code>yield</code> 是一个 <code>throw value</code> 语句。</p>
+
+<p>如果在抛出的异常处理期间没有遇到 <code>yield</code>,则异常将通过调用 <code>throw()</code> 向上传播,对 <code>next()</code> 的后续调用将导致 <code>done</code> 属性为 <code>true</code>。</p>
+
+<p>生成器具有 {{jsxref("Global_Objects/Generator/return","return(value)")}} 方法,返回给定的值并完成生成器本身。</p>
+
+<p>{{PreviousNext("Web/JavaScript/Guide/Using_promises", "Web/JavaScript/Guide/Meta_programming")}}</p>
diff --git a/files/zh-cn/web/javascript/guide/javascript_overview/index.html b/files/zh-cn/web/javascript/guide/javascript_overview/index.html
new file mode 100644
index 0000000000..1828016f32
--- /dev/null
+++ b/files/zh-cn/web/javascript/guide/javascript_overview/index.html
@@ -0,0 +1,135 @@
+---
+title: JavaScript 概述
+slug: Web/JavaScript/Guide/JavaScript_Overview
+tags:
+ - ECMAScript
+translation_of: Web/JavaScript/Guide/Introduction
+---
+<p>本节将介绍并讨论 JavaScript 的基本概念。</p>
+
+<h2 id="What_is_JavaScript.3F" name="What_is_JavaScript.3F">什么是 JavaScript?</h2>
+
+<p>JavaScript 是一种跨平台,面向对象的脚本语言。作为一种小巧且轻量级的语言,JavaScript 无意于独立运行,而是被设计为可以轻易嵌入到其它的产品和应用中,比如 Web 浏览器。在宿主环境中,JavaScript 可以被连接到环境中的对象之上,以提供对其的编程控制。</p>
+
+<p>核心的 JavaScript 中包含有一组核心的对象,包括 <code>Array,</code><code>Date</code> 和 <code>Math</code>,以及一组核心的语言要素,包括操作符,控制结构和语句。出于多种目的,可以通过为其增补附加的对象,对核心 JavaScript 加以扩展;例如:</p>
+
+<ul>
+ <li><em>客户端 JavaScript</em> 提供了用于控制浏览器(Navigator 或者其它浏览器)以及其中的文档对象模型(DOM)的对象,从而扩展了核心 JavaScript。例如,客户端扩展允许应用程序在 HTML 的表单中加入元素,以便响应用户事件,比如鼠标点击,表单输入和页面导航。</li>
+ <li><em>服务器端 JavaScript</em> 提供了服务于在服务器上运行 JavaScript 的对象,从而扩展了核心 JavaScript。例如,服务器端扩展可以允许应用程序访问关系型数据库,在应用程序的不同调用间提供信息的连续性,甚至于处理服务器之上的文件。</li>
+</ul>
+
+<p>借由 JavaScript 的 LiveConnect 功能,您可以让 Java 和 JavaScript 间实现通讯。从 JavaScript 中,您可以创建 Java 对象并访问它们的公共方法和域。从 Java 中,也可以访问 JavaScript 的对象,属性和方法。</p>
+
+<p>Netscape 发明了 JavaScript 并将 JavaScript 首先用于 Netscape 浏览器中。</p>
+
+<h2 id="JavaScript_and_Java" name="JavaScript_and_Java">JavaScript 和 Java</h2>
+
+<p>JavaScript 和 Java 虽然在某些方面相似,但在另外一些方面确有着本质的不同。JavaScript 语言类似于 Java 语言,但是没有 Java 的类型静态化和强类型检查。JavaScript 大部分的表达式语法,命名规范以及基本的控制流构成都和 Java 相同。正是由于这个原因,JavaScript 才从 LiveScript 改名得来。</p>
+
+<p>不同于 Java 的通过声明而形成的编译时的类系统,JavaScript 支持基于少量数据类型的运行时系统,这些数据类型用以表示数值、布尔值和字符串。JavaScript 使用基于原型的对象模型,而不是更常见的基于类的对象模型。基于原型的对象模型提供了动态的继承能力,实际上,究竟什么得到继承,对于每个对象都可能不同。JavaScript 还支持无需任何特殊的声明要求的函数。函数可以作为对象的属性,当成松散类型方法(loosely typed method)来执行。</p>
+
+<p>相比 Java 而言,JavaScript 是一种格式相当自由的语言。无需声明所有的变量,类和方法。无需关心方法是公共的,私有的或者是保护的,也无需实现接口。变量,参数,以及返回值都无需显式的类型声明。</p>
+
+<p>Java 是基于类的编程语言,目标在于快速的执行和类型安全。这里的类型安全,可以是比如,你不能将 Java 的整数强制转换为对象引用,或者通过篡改 Java 字节码来达到访问私有内存区域的目的。Java 基于类的模型意味着程序完全由类及其方法构成。这些类的继承以及强类型通常需要紧密耦合的对象层级结构。这些需求使得 Java 编程远比 JavaScript 编程要复杂。</p>
+
+<p>相比之下,JavaScript 的设计理念源于一系列更小巧的动态类型语言,比如 HyperTalk 和 dBASE。这些脚本语言以其更为简单的语法,更专业化的内建功能,以及最小化的对象创建需求,提供了更为大众化的编程工具。</p>
+
+<table class="standard-table">
+ <caption>表 1.1 JavaScript 与 Java 的对比</caption>
+ <thead>
+ <tr>
+ <th scope="col">JavaScript</th>
+ <th scope="col">Java</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>面向对象的。对象的类型间没有区别。继承是基于原型机制实现的,且属性和方法可以动态地添加到任何对象之上。</td>
+ <td>基于类的。对象被划分为类和实例,且所有的继承是通过类的层级结构实现的。类或者实例不能动态地添加属性或方法。</td>
+ </tr>
+ <tr>
+ <td>变量的数据类型无需声明(动态化类型)。</td>
+ <td>变量的数据类型必需声明(静态化类型)。</td>
+ </tr>
+ <tr>
+ <td>不能自动地写入硬盘</td>
+ <td>不能自动地写入硬盘</td>
+ </tr>
+ </tbody>
+</table>
+
+<p>有关 JavaScript 和 Java 之间区别的更多信息,参见 <a href="/zh-CN/docs/JavaScript/Guide/Details_of_the_Object_Model" title="JavaScript/Guide/Details of the Object Model">对象模型的细节</a>。</p>
+
+<h2 id="JavaScript_and_the_ECMAScript_Specification" name="JavaScript_and_the_ECMAScript_Specification">JavaScript 和 ECMAScript 规范</h2>
+
+<p>Netscape 发明了 JavaScript 并将 JavaScript 首先用于 Netscape 浏览器中。不过, Netscape 正在与 <a class="external" href="http://www.ecma-international.org/">Ecma International</a> — 欧洲信息和通讯标准化协会(ECMA 曾是 European Computer Manufacturers Association,既欧洲计算机制造商协会的缩写)一道致力于交付一个基于核心 JavaScript 的,标准化的,国际化的编程语言,既 ECMAScript。ECMAScript 在所有支持该标准的应用程序中具有相同的特性。其它公司可以使用开放的标准语言来开发它们的 JavaScript 实现。ECMAScript 标准在 ECMA-262 规范中加以记述。</p>
+
+<p>ECMA-262 标准由 <a class="external" href="http://www.iso.ch/">ISO</a>(International Organization for Standardization,既国际化标准化组织)批准为 ISO-16262。在 Mozilla 网站上可以找到 <a class="external" href="http://www-archive.mozilla.org/js/language/E262-3.pdf" title="http://www-archive.mozilla.org/js/language/E262-3.pdf">PDF 版本的 ECMA-262</a> (过时的版本)。在 <a class="external" href="http://www.ecma-international.org/publications/standards/Ecma-262.htm">Ecma International 的网站</a> 上也可以找到该规范。ECMAScript 规范没有描述文档对象模型(DOM)。该模型由 <a class="external" href="http://www.w3.org/">World Wide Web Consortium (W3C)</a> 完成标准化。DOM 定义了 HTML 文档对象呈现在脚本中的方式。</p>
+
+<h3 id="Relationship_between_JavaScript_Versions_and_ECMAScript_Editions" name="Relationship_between_JavaScript_Versions_and_ECMAScript_Editions">JavaScript 版本和 ECMAScript 版本之间的关系</h3>
+
+<p>Netscape 与 Ecma International 的紧密合作形成了 ECMAScript 规范(ECMA-262)。下面的表格描述了 JavaScript 版本和 ECMAScript 版本之间的关系。</p>
+
+<table class="standard-table">
+ <caption>表 1.2 JavaScript 版本和 ECMAScript 版本</caption>
+ <thead>
+ <tr>
+ <th scope="row">JavaScript 版本</th>
+ <th scope="col">与 ECMAScript 版本的关系</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>JavaScript 1.1</td>
+ <td>ECMA-262,第 1 版 基于 JavaScript 1.1.</td>
+ </tr>
+ <tr>
+ <td>JavaScript 1.2</td>
+ <td>ECMA-262 在 JavaScript 1.2 发布时尚未完成。由于以下原因,JavaScript 1.2 并不与 ECMA-262,第 1 版完全兼容:
+ <ul>
+ <li>Netscape 在 JavaScript 1.2 开发了一些新的特性尚未被 ECMA-262 采纳。</li>
+ <li>ECMA-262 添加了两项新特性:基于 Unicode 的国际化,以及跨平台的一致行为。而 JavaScript 1.2 的某些特性,例如 <code>Date</code> 对象,是依赖于平台的,且具有特定于平台的行为。</li>
+ </ul>
+ </td>
+ </tr>
+ <tr>
+ <td>JavaScript 1.3</td>
+ <td>JavaScript 1.3 完全兼容于 ECMA-262,第 1 版。<br>
+ JavaScript 1.3 解决了 JavaScript 1.2 与 ECMA-262 之间的不一致性,同时保留了 JavaScript 1.2 中的附加特性,除了  <code>==</code> 和 <code>!= 被修改以便顺应于</code> ECMA-262 之外。</td>
+ </tr>
+ <tr>
+ <td>JavaScript 1.4</td>
+ <td>JavaScript 1.4 完全兼容于 ECMA-262,第 1 版。<br>
+ ECMAScript 规范的第三版在 JavaScript 1.4 发布时尚未最终完成。</td>
+ </tr>
+ <tr>
+ <td>JavaScript 1.5</td>
+ <td>JavaScript 1.5 完全兼容于 ECMA-262,第 3 版。</td>
+ </tr>
+ </tbody>
+</table>
+
+<div class="note"><strong>注:</strong>ECMA-262,第 2 版仅包含对第 1 版规范的细微的编辑性的改动和错误修正。由 Ecma International 的 TC39 工作组发布的最新版本为 ECMAScript 版本 5.1</div>
+
+<p><a href="/en-US/docs/JavaScript/Reference" title="JavaScript/Reference">JavaScript 参考</a> 中标明了语言中的哪些特性兼容于 ECMAScript。</p>
+
+<p>JavaScript 将总会包含某些 ECMAScript 规范中所没有的特性;JavaScript 兼容于 ECMAScript,同时提供附加特性。</p>
+
+<h3 id="JavaScript_Documentation_versus_the_ECMAScript_Specification" name="JavaScript_Documentation_versus_the_ECMAScript_Specification">JavaScript 文档相较于 ECMAScript 规范</h3>
+
+<p>ECMAScript 规范了实现 ECMAScript 的一组需求;它有助于您确定某项 JavaScript 特性是否也为其它 ECMAScript 的实现所支持。如果您想编写仅仅使用 ECMAScript 所支持的特性的代码,那么您可能需要参考 ECMAScript 规范。</p>
+
+<p>ECMAScript 文档的目的不在于帮助脚本程序员;关于脚本编写的信息,请参考 JavaScript 文档。</p>
+
+<h3 id="JavaScript_and_ECMAScript_Terminology" name="JavaScript_and_ECMAScript_Terminology">JavaScript 和 ECMAScript 术语</h3>
+
+<p>ECMAScript 规范使用的术语和语法对于 JavaScript 程序员而言,可能会有点陌生。尽管对语言的描述方式在 ECMAScript 中可能不尽相同,但是语言本身还是相同的。JavaScript 支持 ECMAScript 规范中所勾勒出的全部功能。</p>
+
+<p>JavaScript 文档描述了语言中适合于 JavaScript 程序员的方面。例如:</p>
+
+<ul>
+ <li>JavaScript 文档中没有描述全局对象,因为不会直接用到它。全局对象的属性和方法在 JavaScript 文档中被称为顶层函数和属性。</li>
+ <li>JavaScript 文档中没有讨论 <code>Number</code> 和 <code>String</code> 对象的无参(零个参数)构造器,因为几乎不会用到其生成的对象。无参的 <code>Number</code> 构造器返回 +0,而无参的 <code>String</code> 构造器返回 "" (空的字符串)。</li>
+</ul>
+
+<div>{{ PreviousNext("JavaScript/Guide/About", "JavaScript/Guide/Values,_variables,_and_literals") }}</div>
diff --git a/files/zh-cn/web/javascript/guide/keyed_collections/index.html b/files/zh-cn/web/javascript/guide/keyed_collections/index.html
new file mode 100644
index 0000000000..0c10c93c2a
--- /dev/null
+++ b/files/zh-cn/web/javascript/guide/keyed_collections/index.html
@@ -0,0 +1,155 @@
+---
+title: 带键的集合
+slug: Web/JavaScript/Guide/Keyed_collections
+tags:
+ - Guide
+ - JavaScript
+ - Map
+ - set
+ - 集合
+translation_of: Web/JavaScript/Guide/Keyed_collections
+---
+<div>{{jsSidebar("JavaScript Guide")}} {{PreviousNext("Web/JavaScript/Guide/Indexed_Collections", "Web/JavaScript/Guide/Working_with_Objects")}}</div>
+
+<p class="summary">这一章介绍由key值标记的数据容器;Map 和 Set 对象承载的数据元素可以按照插入时的顺序被迭代遍历。</p>
+
+<h2 id="映射">映射</h2>
+
+<h3 id="Map对象"><code>Map</code>对象</h3>
+
+<p>ECMAScript 2015 引入了一个新的数据结构来将一个值映射到另一个值。一个{{jsxref("Map")}}对象就是一个简单的键值对映射集合,可以按照数据插入时的顺序遍历所有的元素。</p>
+
+<p>下面的代码演示了使用<code>Map</code>进行的一些基本操作。请参考{{jsxref("Map")}}以获取更多的样例和完整的 API。你可以使用{{jsxref("Statements/for...of","for...of")}}循环来得到所有的<code>[key, value]</code>。</p>
+
+<pre class="brush: js">var sayings = new Map();
+sayings.set('dog', 'woof');
+sayings.set('cat', 'meow');
+sayings.set('elephant', 'toot');
+sayings.size; // 3
+sayings.get('fox'); // undefined
+sayings.has('bird'); // false
+sayings.delete('dog');
+sayings.has('dog'); // false
+
+for (var [key, value] of sayings) {
+ console.log(key + ' goes ' + value);
+}
+// "cat goes meow"
+// "elephant goes toot"
+
+sayings.clear();
+sayings.size; // 0</pre>
+
+<h3 id="Object和Map的比较"><code><font face="Consolas, Liberation Mono, Courier, monospace">Object</font></code>和<code>Map</code>的比较</h3>
+
+<p>一般地,{{jsxref("Object", "objects", "", 1)}}会被用于将字符串类型映射到数值。<code>Object</code>允许设置键值对、根据键获取值、删除键、检测某个键是否存在。而<code>Map</code>具有更多的优势。</p>
+
+<ul>
+ <li><code>Object</code>的键均为<code>Strings</code>类型,在<code>Map</code>里键可以是任意类型。</li>
+ <li>必须手动计算<code>Object</code>的尺寸,但是可以很容易地获取使用<code>Map</code>的尺寸。</li>
+ <li><code>Map</code>的遍历遵循元素的插入顺序。</li>
+ <li><code>Object</code>有原型,所以映射中有一些缺省的键。<font face="Open Sans, Arial, sans-serif">(</font>可以用 <code>map = Object.create(null) 回避</code>)。</li>
+</ul>
+
+<p>这三条提示可以帮你决定用<code>Map</code>还是<code>Object</code>:</p>
+
+<ul>
+ <li>如果键在运行时才能知道,或者所有的键类型相同,所有的值类型相同,那就使用<code>Map</code>。</li>
+ <li>如果需要将原始值存储为键,则使用<code>Map</code>,因为<code>Object</code>将每个键视为字符串,不管它是一个数字值、布尔值还是任何其他原始值。</li>
+ <li>如果需要对个别元素进行操作,使用<code>Object</code>。</li>
+</ul>
+
+<h3 id="WeakMap对象"><code>WeakMap</code>对象</h3>
+
+<p>{{jsxref("WeakMap")}}对象也是键值对的集合。它的<strong>键必须是对象类型</strong>,值可以是任意类型。它的键被弱保持,也就是说,当其键所指对象没有其他地方引用的时候,它会被GC回收掉。<code>WeakMap</code>提供的接口与<code>Map</code>相同。</p>
+
+<p>与<code>Map</code>对象不同的是,<code>WeakMap</code>的键是不可枚举的。不提供列出其键的方法。列表是否存在取决于垃圾回收器的状态,是不可预知的。</p>
+
+<p>可以在"Why <em>Weak</em>Map?"{{jsxref("WeakMap")}}查看更多信息和示例。</p>
+
+<p><code>WeakMap</code>对象的一个用例是存储一个对象的私有数据或隐藏实施细节。Nick Fitzgerald 的博文<a href="http://fitzgeraldnick.com/weblog/53/">"Hiding Implementation Details with ECMAScript 6 WeakMaps"</a>提供了一个例子。对象内部的私有数据和方法被存储在<code>WeakMap</code>类型的<code>privates</code>变量中。所有暴露出的原型和情况都是公开的,而其他内容都是外界不可访问的,因为模块并未导出<code>privates</code>对象。</p>
+
+<pre class="brush: js">const privates = new WeakMap();
+
+function Public() {
+ const me = {
+ // Private data goes here
+ };
+ privates.set(this, me);
+}
+
+Public.prototype.method = function () {
+ const me = privates.get(this);
+ // Do stuff with private data in `me`...
+};
+
+module.exports = Public;
+</pre>
+
+<h2 id="集合">集合</h2>
+
+<h3 id="Set对象"><code>Set</code>对象</h3>
+
+<p>{{jsxref("Set")}}对象是一组值的集合,这些值是不重复的,可以按照添加顺序来遍历。</p>
+
+<p>这里演示了<code>Set</code>的基本操作,更多示例和完整API可以参考{{jsxref("Set")}}。</p>
+
+<pre class="brush: js">var mySet = new Set();
+mySet.add(1);
+mySet.add("some text");
+mySet.add("foo");
+
+mySet.has(1); // true
+mySet.delete("foo");
+mySet.size; // 2
+
+for (let item of mySet) console.log(item);
+// 1
+// "some text"
+</pre>
+
+<h3 id="数组和集合的转换">数组和集合的转换</h3>
+
+<p>可以使用{{jsxref("Array.from")}}或<a href="/zh-CN/docs/Web/JavaScript/Reference/Operators/Spread_operator">展开操作符</a>来完成集合到数组的转换。同样,<code>Set</code>的构造器接受数组作为参数,可以完成从<code>Array</code>到<code>Set</code>的转换。需要重申的是,<code>Set</code>对象中的值不重复,所以数组转换为集合时,所有重复值将会被删除。</p>
+
+<pre class="brush: js">Array.from(mySet);
+[...mySet2];
+
+mySet2 = new Set([1,2,3,4]);
+</pre>
+
+<h3 id="Array和Set的对比"><code>Array</code>和<code>Set</code>的对比</h3>
+
+<p>一般情况下,在JavaScript中使用数组来存储一组元素,而新的集合对象有这些优势:</p>
+
+<ul>
+ <li>数组中用于判断元素是否存在的{{jsxref("Array.indexOf", "indexOf")}} 函数效率低下。</li>
+ <li><code>Set</code>对象允许根据值删除元素,而数组中必须使用基于下标的 splice 方法。</li>
+ <li>数组的<code>indexOf</code>方法无法找到{{jsxref("NaN")}}值。</li>
+ <li><code>Set</code>对象存储不重复的值,所以不需要手动处理包含重复值的情况。</li>
+</ul>
+
+<h3 id="WeakSet对象"><code>WeakSet</code>对象</h3>
+
+<p>{{jsxref("WeakSet")}}对象是一组对象的集合。<code>WeakSet</code>中的对象不重复且不可枚举<font face="Consolas, Liberation Mono, Courier, monospace">。</font></p>
+
+<p>与{{jsxref("Set")}}对象的主要区别有:</p>
+
+<ul>
+ <li><code>WeakSets</code>中的值必须是对象类型,不可以是别的类型</li>
+ <li><code>WeakSet</code>的“<em>weak</em>”指的是,对集合中的对象,如果不存在其他引用,那么该对象将可被垃圾回收。于是不存在一个当前可用对象组成的列表,所以<code>WeakSets</code>不可枚举</li>
+</ul>
+
+<p><code>WeakSet</code>的用例很有限,比如使用DOM元素作为键来追踪它们而不必担心内存泄漏。</p>
+
+<h2 id="Map的键和Set的值的等值判断"><code>Map</code>的键和<code>Set</code>的值的等值判断</h2>
+
+<p><code>Map</code>的键和<code>Set</code>的值的等值判断都基于<a href="https://people.mozilla.org/~jorendorff/es6-draft.html#sec-samevaluezero">same-value-zero algorithm</a>:</p>
+
+<ul>
+ <li>判断使用与<code>===</code>相似的规则。</li>
+ <li><code>-0</code>和<code>+0</code>相等。</li>
+ <li>{{jsxref("NaN")}}与自身相等(与<code>===</code>有所不同)。</li>
+</ul>
+
+<p>{{PreviousNext("Web/JavaScript/Guide/Indexed_Collections", "Web/JavaScript/Guide/Working_with_Objects")}}</p>
diff --git a/files/zh-cn/web/javascript/guide/loops_and_iteration/index.html b/files/zh-cn/web/javascript/guide/loops_and_iteration/index.html
new file mode 100644
index 0000000000..9c82f49588
--- /dev/null
+++ b/files/zh-cn/web/javascript/guide/loops_and_iteration/index.html
@@ -0,0 +1,409 @@
+---
+title: 循环与迭代
+slug: Web/JavaScript/Guide/Loops_and_iteration
+tags:
+ - JavaScript
+ - 循环
+ - 指南
+ - 语法
+translation_of: Web/JavaScript/Guide/Loops_and_iteration
+---
+<div>{{jsSidebar("JavaScript Guide")}} {{PreviousNext("Web/JavaScript/Guide/Control_flow_and_error_handling", "Web/JavaScript/Guide/Functions")}}</div>
+
+<p class="summary">循环提供了一种快速和简单的方式去做一些重复的事。<a href="/en-US/docs/Web/JavaScript/Guide">JavaScript入门</a>的这个章节会介绍在JavaScript中存在哪些不同的迭代语句。</p>
+
+<p>你可以把循环想成一种计算机化的游戏,告诉某人在一个方向上走X步,然后在另一个方向上走Y步;例如,“向东走5步”可以用一个循环来这样表达:</p>
+
+<pre class="brush: js">var step;
+for (step = 0; step &lt; 5; step++) {
+ // Runs 5 times, with values of step 0 through 4.
+ console.log('Walking east one step');
+}
+</pre>
+
+<p>循环有很多种类,但本质上它们都做的是同一件事:它们把一个动作重复了很多次(实际上重复的次数有可能为 0)。各种循环机制提供了不同的方法去确定循环的开始和结束。不同情况下,某一种类型循环会比其它的循环用起来更简单。</p>
+
+<p>JavaScript中提供了这些循环语句:</p>
+
+<ul>
+ <li>{{anch("for 语句")}}</li>
+ <li>{{anch("do...while 语句")}}</li>
+ <li>{{anch("while 语句")}}</li>
+ <li>{{anch("labeled 语句")}}</li>
+ <li>{{anch("break 语句")}}</li>
+ <li>{{anch("continue 语句")}}</li>
+ <li>{{anch("for...in 语句")}}</li>
+ <li>{{anch("for...of 语句")}}</li>
+</ul>
+
+<h2 id="for_语句"><code>for</code> 语句</h2>
+
+<p>一个 {{jsxref("statements/for","for")}} 循环会一直重复执行,直到指定的循环条件为 false。 JavaScript 的 for 循环,和 Java、C 的 for 循环,是很相似的。一个 for 语句是这个样子的:</p>
+
+<pre class="syntaxbox">for ([initialExpression]; [condition]; [incrementExpression])
+ statement
+</pre>
+
+<p>当一个 <code>for</code> 循环执行的时候,会发生以下过程:</p>
+
+<ol>
+ <li>如果有初始化表达式 <code>initialExpression</code>,它将被执行。这个表达式通常会初始化一个或多个循环计数器,但语法上是允许一个任意复杂度的表达式的。这个表达式也可以声明变量。</li>
+ <li>计算 <code>condition</code> 表达式的值。如果 <code>condition</code> 的值是 true,循环中的语句会被执行。如果 <code>condition</code> 的值是 false,<code>for</code> 循环终止。如果 <code>condition</code> 表达式整个都被省略掉了,condition的值会被认为是true。</li>
+ <li>循环中的 <code>statement</code> 被执行。如果需要执行多条语句,可以使用块(<code>{ ... }</code>)来包裹这些语句。</li>
+ <li>如果有更新表达式 <code>incrementExpression</code>,执行更新表达式。</li>
+ <li>回到步骤 2。</li>
+</ol>
+
+<h3 id="例子"><strong>例子</strong></h3>
+
+<p>下面的函数包含一个含有 <code>for</code> 循环去计算一个滑动列表中被选中项目的个数(一个 {{HTMLElement("select")}} 元素允许选择多项)。<code>for</code> 循环声明了变量i并将它的初始值设为 0。它检查 <code>i</code> 是否比 <code>&lt;select&gt;</code> 元素中的选项数量少,执行了随后的 <code>if</code> 语句,然后在每次完成循环后,<code>i</code> 的值增加 1。</p>
+
+<pre class="brush: html">&lt;form name="selectForm"&gt;
+ &lt;p&gt;
+ &lt;label for="musicTypes"&gt;Choose some music types, then click the button below:&lt;/label&gt;
+ &lt;select id="musicTypes" name="musicTypes" multiple="multiple"&gt;
+ &lt;option selected="selected"&gt;R&amp;B&lt;/option&gt;
+ &lt;option&gt;爵士&lt;/option&gt;
+ &lt;option&gt;布鲁斯&lt;/option&gt;
+ &lt;option&gt;新纪元&lt;/option&gt;
+ &lt;option&gt;古典&lt;/option&gt;
+ &lt;option&gt;歌剧&lt;/option&gt;
+ &lt;/select&gt;
+ &lt;/p&gt;
+ &lt;p&gt;&lt;input id="btn" type="button" value="选择了多少个选项?" /&gt;&lt;/p&gt;
+&lt;/form&gt;
+
+&lt;script&gt;
+function howMany(selectObject) {
+ var numberSelected = 0;
+ for (var i = 0; i &lt; selectObject.options.length; i++) {
+ if (selectObject.options[i].selected) {
+ numberSelected++;
+ }
+ }
+ return numberSelected;
+}
+
+var btn = document.getElementById("btn");
+btn.addEventListener("click", function(){
+ alert('选择选项的数量是: ' + howMany(document.selectForm.musicTypes))
+});
+&lt;/script&gt;
+
+</pre>
+
+<h2 id="do...while_语句"><code>do...while</code> 语句</h2>
+
+<p>{{jsxref("statements/do...while", "do...while")}} 语句一直重复直到指定的条件求值得到假值(false)。 一个 do...while 语句看起来像这样:</p>
+
+<pre class="syntaxbox">do
+ statement
+while (condition);
+</pre>
+
+<p><code>statement</code> 在检查条件之前会执行一次。要执行多条语句(语句块),要使用块语句(<code>{ ... }</code>)包括起来。 如果 <code>condition</code> 为真(true),<code>statement</code> 将再次执行。 在每个执行的结尾会进行条件的检查。当 <code>condition</code> 为假(false),执行会停止并且把控制权交回给 <code>do...while</code> 后面的语句。</p>
+
+<h3 id="例子_2"><strong>例子</strong></h3>
+
+<p>在下面的例子中, 这个 <code>do</code> 循环将至少重复一次,并且一直重复直到 <code>i</code> 不再小于 5。</p>
+
+<pre class="brush: js">var i = 0;
+do {
+ i += 1;
+ console.log(i);
+} while (i &lt; 5);</pre>
+
+<h2 id="while_语句"><code>while</code> 语句</h2>
+
+<p>一个 {{jsxref("statements/while","while")}} 语句只要指定的条件求值为真(true)就会一直执行它的语句块。一个 <code>while</code> 语句看起来像这样:</p>
+
+<pre class="syntaxbox">while (condition)
+ statement
+</pre>
+
+<p>如果这个条件变为假,循环里的 <code>statement</code> 将会停止执行并把控制权交回给 <code>while</code> 语句后面的代码。</p>
+
+<p>条件检测会在每次 <code>statement</code> 执行之前发生。如果条件返回为真, <code>statement</code> 会被执行并紧接着再次测试条件。如果条件返回为假,执行将停止并把控制权交回给 while 后面的语句。</p>
+
+<p>要执行多条语句(语句块),要使用语句块 (<code>{ ... }</code>) 包括起来。</p>
+
+<h3 id="例子_1"><strong>例子 1</strong></h3>
+
+<p>只要 <code>n</code> 小于 3,下面的 <code>while</code> 循环就会一直执行:</p>
+
+<pre class="brush: js">var n = 0;
+var x = 0;
+while (n &lt; 3) {
+ n++;
+ x += n;
+}
+</pre>
+
+<p>在每次循环里, <code>n</code> 会增加 1,并被加到 <code>x</code> 上。所以, x 和 n 的变化是:</p>
+
+<ul>
+ <li>第一次完成后:<code>n</code> = 1,<code>x</code> = 1</li>
+ <li>第二次完成后:<code>n</code> = 2,<code>x</code> = 3</li>
+ <li>第三次完成后:<code>n</code> = 3,<code>x</code> = 6</li>
+</ul>
+
+<p>在三次完成后, 条件 <code>n &lt; 3</code> 的结果不再为真,所以循环终止了。</p>
+
+<h3 id="例子_2_2"><strong>例子 2</strong></h3>
+
+<p>避免无穷循环(无限循环)。保证循环的条件结果最终会变成假;否则,循环永远不会停止。因为条件永远不会变成假值,下面这个 while 循环将会永远执行:</p>
+
+<pre class="brush: js">while (true) {
+ console.log("Hello, world");
+}</pre>
+
+<h2 id="label_语句"><code>label</code> 语句</h2>
+
+<p>一个 {{jsxref("statements/label","label")}} 提供了一个让你在程序中其他位置引用它的标识符。例如,你可以用 label 标识一个循环, 然后使用 <code>break</code> 或者 <code>continue</code> 来指出程序是否该停止循环还是继续循环。</p>
+
+<p>label 语句的语法看起来像这样:</p>
+
+<pre class="syntaxbox">label :
+ statement
+</pre>
+
+<p><code>label</code> 的值可以是任何的非保留字的 JavaScript 标识符, <code>statement</code> 可以是任意你想要标识的语句(块)。</p>
+
+<h3 id="例子_3"><strong>例子</strong></h3>
+
+<p>在这个例子里,标记 <code>markLoop</code> 标识了一个 <code>while</code> 循环。</p>
+
+<pre class="brush: js">markLoop:
+while (theMark == true) {
+ doSomething();
+}</pre>
+
+<p>举一个比较典型的例子,看完后即明白 Label 的应用:</p>
+
+<p>未添加 Label:</p>
+
+<pre class="brush: js">var num = 0;
+for (var i = 0 ; i &lt; 10 ; i++) { // i 循环
+ for (var j = 0 ; j &lt; 10 ; j++) { // j 循环
+ if( i == 5 &amp;&amp; j == 5 ) {
+ break; // i = 5,j = 5 时,会跳出 j 循环
+ } // 但 i 循环会继续执行,等于跳出之后又继续执行更多次 j 循环
+ num++;
+ }
+}
+
+alert(num); // 输出 95</pre>
+
+<p>添加 Label 后:</p>
+
+<pre class="brush: js">var num = 0;
+outPoint:
+for (var i = 0 ; i &lt; 10 ; i++){
+ for (var j = 0 ; j &lt; 10 ; j++){
+ if( i == 5 &amp;&amp; j == 5 ){
+ break outPoint; // 在 i = 5,j = 5 时,跳出所有循环,
+ // 返回到整个 outPoint 下方,继续执行
+ }
+ num++;
+ }
+}
+
+alert(num); // 输出 55</pre>
+
+<p>使用 continue 语句,则可达到与未添加 label 相同的效果,但在这种有多层循环的情况下,循环的跳出进入流程更为明晰一些:</p>
+
+<pre class="brush: js">var num = 0;
+outPoint:
+for(var i = 0; i &lt; 10; i++) {
+ for(var j = 0; j &lt; 10; j++) {
+ if(i == 5 &amp;&amp; j == 5) {
+ continue outPoint;
+ }
+ num++;
+ }
+}
+alert(num); // 95</pre>
+
+<p>从alert(num)的值可以看出,continue outPoint; 语句的作用是跳出当前循环,并跳转到outPoint(标签)下的 for 循环继续执行。</p>
+
+<h2 id="break_语句"><code>break</code> 语句</h2>
+
+<p>使用 {{jsxref("statements/break","break")}} 语句来终止循环,<code>switch</code>, 或者是链接到 label 语句。</p>
+
+<ul>
+ <li>当你使用不带 label 的 <code>break</code> 时, 它会立即终止当前所在的 <code>while</code>,<code>do-while</code>,<code>for</code>,或者 <code>switch</code> 并把控制权交回这些结构后面的语句。</li>
+ <li>当你使用带 label 的 <code>break</code> 时,它会终止指定的带标记(label)的语句。</li>
+</ul>
+
+<p><code>break</code> 语句的语法看起来像这样:</p>
+
+<pre class="syntaxbox">break [label];</pre>
+
+<p>在语法中,被 <code>[]</code> 包裹的内容是可省略的,也就是 <code>label</code> 可以省略。若省略,则终止当前所在的循环或 <code>switch</code>;若不省略,则终止指定的 label 语句。</p>
+
+<h3 id="例子_1_2"><strong>例子</strong> <strong>1</strong></h3>
+
+<p>下面的例子循环数组里的元素,直到找到一个等于 <code>theValue</code> 的值:</p>
+
+<pre class="brush: js">for (i = 0; i &lt; a.length; i++) {
+ if (a[i] == theValue) {
+ break;
+ }
+}</pre>
+
+<h3 id="例子_2_终止一个_label"><strong>例子 2: </strong>终止一个 label</h3>
+
+<pre class="brush: js">var x = 0;
+var z = 0
+labelCancelLoops: while (true) {
+ console.log("外部循环: " + x);
+ x += 1;
+ z = 1;
+ while (true) {
+ console.log("内部循环: " + z);
+ z += 1;
+ if (z === 10 &amp;&amp; x === 10) {
+ break labelCancelLoops;
+ } else if (z === 10) {
+ break;
+ }
+ }
+}
+</pre>
+
+<h2 id="continue_语句"><code>continue</code> 语句</h2>
+
+<p>{{jsxref("statements/continue","continue")}} 语句可以用来继续执行(跳过代码块的剩余部分并进入下一循环)一个 <code>while</code>、<code>do-while</code>、<code>for</code>,或者 <code>label</code> 语句。</p>
+
+<ul>
+ <li>当你使用不带 label 的 <code>continue</code> 时, 它终止当前 <code>while</code>,<code>do-while</code>,或者 for 语句到结尾的这次的循环并且继续执行下一次循环。</li>
+ <li>当你使用带 label 的 <code>continue</code> 时, 它会应用被 label 标识的循环语句。</li>
+</ul>
+
+<p><code>continue</code> 语句的语法看起来像这样:</p>
+
+<pre class="syntaxbox">continue [label];
+</pre>
+
+<h3 id="例子_1_3"><strong>例子 1</strong></h3>
+
+<p>The following example shows a <code>while</code> loop with a <code>continue</code> statement that executes when the value of <code>i</code> is three. Thus, <code>n</code> takes on the values one, three, seven, and twelve.</p>
+
+<pre class="brush: js">var i = 0;
+var n = 0;
+while (i &lt; 5) {
+ i++;
+ if (i == 3) {
+ continue;
+ }
+ n += i;
+ console.log(n);
+}
+//1,3,7,12
+</pre>
+
+<pre class="brush: js">var i = 0;
+var n = 0;
+while (i &lt; 5) {
+ i++;
+ if (i == 3) {
+ // continue;
+ }
+ n += i;
+ console.log(n);
+}
+// 1,3,6,10,15</pre>
+
+<h3 id="例子_2_3"><strong>例子 2</strong></h3>
+
+<p>一个被标签为 <code>checkiandj</code> 的语句包含了一个标签为 <code>checkj</code> 的语句。</p>
+
+<p>如果遇到 <code>continue</code> 语句,程序会结束当前 <code>chechj</code> 的迭代并开始下一轮的迭代。</p>
+
+<p>每次遇到 <code>continue</code> 语句时,<code>checkj</code> 语句会一直重复执行,直到 <code>checkj</code> 语句的条件为 <code>false</code>。</p>
+
+<p>当返回<code> false</code> 后,将会执行 <code>checkiandj</code> 的剩余语句,<code>checkiandj</code> 会一直执行,直到 <code>checkiandj</code> 的条件为 <code>false</code>。</p>
+
+<p>当 <code>checkiandj</code> 的返回值为 <code>false</code> 时,将会执行 <code>checkiandj</code> 的下面的语句。</p>
+
+<p>如果 <code>continue</code> 有一个标记 <code>checkiandj</code>, 程序将会从 <code>checkiandj</code> 语句块的顶部继续执行。</p>
+
+<pre class="brush: js">var i = 0;
+var j = 10;
+checkiandj:
+ while (i &lt; 4) {
+ console.log(i);
+ i += 1;
+ checkj:
+ while (j &gt; 4) {
+ console.log(j);
+ j -= 1;
+ if ((j % 2) == 0) {
+ continue checkj;
+ }
+ console.log(j + ' 是奇数。');
+ }
+ console.log('i = ' + i);
+ console.log('j = ' + j);
+ }</pre>
+
+<h2 id="for...in_语句"><code>for...in</code> 语句</h2>
+
+<p>{{jsxref("statements/for...in","for...in")}} 语句循环一个指定的变量来循环一个对象所有可枚举的属性。JavaScript 会为每一个不同的属性执行指定的语句。</p>
+
+<pre class="syntaxbox">for (variable in object) {
+ statements
+}
+</pre>
+
+<h3 id="例子_4"><strong>例子</strong></h3>
+
+<p>下面的函数通过它的参数得到一个对象和这个对象的名字。然后循环这个对象的所有属性并且返回一个列出属性名和该属性值的字符串。</p>
+
+<pre class="brush: js">function dump_props(obj, obj_name) {
+ var result = "";
+ for (var i in obj) {
+ result += obj_name + "." + i + " = " + obj[i] + "&lt;br&gt;";
+ }
+ result += "&lt;hr&gt;";
+ return result;
+}
+</pre>
+
+<p>对于一个拥有 <code>make</code> 和 <code>model</code> 属性的 <code>car</code> 对象来说,执行结果 <code>result</code> 是:</p>
+
+<pre class="brush: js">car.make = Ford
+car.model = Mustang
+</pre>
+
+<h3 id="数组"><strong>数组</strong></h3>
+
+<p>虽然使用 <strong>for...in </strong>来迭代数组 {{jsxref("Array")}} 元素听起来很诱人,但是它返回的东西除了数字索引外,还有可能是你自定义的属性名字。因此还是用带有数字索引的传统的 {{jsxref("statements/for","for")}} 循环来迭代一个数组比较好,因为,如果你想改变数组对象,比如添加属性或者方法,<strong>for...in </strong>语句迭代的是自定义的属性,而不是数组的元素。(译者注:下面的 <code>for...of</code> 语句,和 <code><a href="/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach">forEach()</a></code>,也是理想的选择。)</p>
+
+<h2 id="for...of_语句"><code>for...of</code> 语句</h2>
+
+<p>{{jsxref("statements/for...of","for...of")}} 语句在<a href="/zh-CN/docs/Web/JavaScript/Guide/iterable">可迭代对象</a>(包括{{jsxref("Array")}}、{{jsxref("Map")}}、{{jsxref("Set")}}、{{jsxref("functions/arguments","arguments")}} 等等)上创建了一个循环,对值的每一个独特属性调用一次迭代。</p>
+
+<pre class="syntaxbox">for (<em>variable</em> of <em>object</em>) {
+ <em>statement
+</em>}
+</pre>
+
+<p>下面的这个例子展示了 <code>for...of</code> 和 {{jsxref("statements/for...in","for...in")}} 两种循环语句之间的区别。 <code>for...in</code> 循环遍历的结果是数组元素的下标,而 <code>for...of</code> 遍历的结果是元素的值:</p>
+
+<pre class="brush:js">let arr = [3, 5, 7];
+arr.foo = "hello";
+
+for (let i in arr) {
+ console.log(i); // 输出 "0", "1", "2", "foo"
+}
+
+for (let i of arr) {
+ console.log(i); // 输出 "3", "5", "7"
+}
+
+// 注意 for...of 的输出没有出现 "hello"
+// 译者:官方文档不知为何在此使用三个空格来缩进…
+</pre>
+
+<p>{{PreviousNext("Web/JavaScript/Guide/Control_flow_and_error_handling", "Web/JavaScript/Guide/Functions")}}</p>
diff --git a/files/zh-cn/web/javascript/guide/meta_programming/index.html b/files/zh-cn/web/javascript/guide/meta_programming/index.html
new file mode 100644
index 0000000000..723165c93f
--- /dev/null
+++ b/files/zh-cn/web/javascript/guide/meta_programming/index.html
@@ -0,0 +1,264 @@
+---
+title: 元编程
+slug: Web/JavaScript/Guide/Meta_programming
+tags:
+ - Guide
+ - JavaScript
+ - Proxy
+ - Reflect
+translation_of: Web/JavaScript/Guide/Meta_programming
+---
+<div>{{jsSidebar("JavaScript Guide")}} {{PreviousNext("Web/JavaScript/Guide/Iterators_and_Generators", "Web/JavaScript/Guide/Modules")}}</div>
+
+<p class="summary">从ECMAScript 2015 开始,JavaScript 获得了 {{jsxref("Proxy")}} 和 {{jsxref("Reflect")}} 对象的支持,允许你拦截并定义基本语言操作的自定义行为(例如,属性查找,赋值,枚举,函数调用等)。借助这两个对象,你可以在 JavaScript 元级别进行编程。</p>
+
+<h2 id="代理">代理</h2>
+
+<p>在 ECMAScript 6 中引入的 {{jsxref("Proxy")}} 对象可以拦截某些操作并实现自定义行为。例如获取一个对象上的属性:</p>
+
+<pre class="brush: js notranslate">let handler = {
+ get: function(target, name){
+ return name in target ? target[name] : 42;
+}};
+
+let p = new Proxy({}, handler);
+p.a = 1;
+
+console.log(p.a, p.b); // 1, 42
+</pre>
+
+<p><code>Proxy</code> 对象定义了一个目标(这里是一个空对象)和一个实现了 <code>get</code> 陷阱的 handler 对象。这里,代理的对象在获取未定义的属性时不会返回 <code>undefined</code>,而是返回 42。</p>
+
+<p>更多例子参见 {{jsxref("Proxy")}} 页面 。</p>
+
+<h3 id="术语">术语</h3>
+
+<p>在讨论代理的功能时会用到以下术语。</p>
+
+<dl>
+ <dt>{{jsxref("Global_Objects/Proxy/handler","handler")}}</dt>
+ <dd>包含陷阱的占位符对象。</dd>
+ <dt>traps</dt>
+ <dd>提供属性访问的方法。这类似于操作系统中陷阱的概念。</dd>
+ <dt>target</dt>
+ <dd>代理虚拟化的对象。它通常用作代理的存储后端。根据目标验证关于对象不可扩展性或不可配置属性的不变量(保持不变的语义)。</dd>
+ <dt>invariants</dt>
+ <dd>实现自定义操作时保持不变的语义称为不变量。如果你违反处理程序的不变量,则会抛出一个 {{jsxref("TypeError")}}。</dd>
+</dl>
+
+<h2 id="句柄和陷阱">句柄和陷阱</h2>
+
+<p>以下表格中总结了 <code>Proxy</code> 对象可用的陷阱。详细的解释和例子请看<a href="/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Proxy/handler">参考页</a>。</p>
+
+<table class="standard-table">
+ <thead>
+ <tr>
+ <th>Handler / trap</th>
+ <th>Interceptions</th>
+ <th>Invariants</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>{{jsxref("Global_Objects/Proxy/handler/getPrototypeOf", "handler.getPrototypeOf()")}}</td>
+ <td>{{jsxref("Object.getPrototypeOf()")}}<br>
+ {{jsxref("Reflect.getPrototypeOf()")}}<br>
+ {{jsxref("Object/proto", "__proto__")}}<br>
+ {{jsxref("Object.prototype.isPrototypeOf()")}}<br>
+ {{jsxref("Operators/instanceof", "instanceof")}}</td>
+ <td>
+ <ul>
+ <li><code>getPrototypeOf</code>方法一定返回一个对象或<code>null</code>.</li>
+ <li>如果 <code>target</code> 不可扩展,<code>Object.getPrototypeOf(proxy)</code> 必须返回和 <code>Object.getPrototypeOf(target)</code>一样的值。</li>
+ </ul>
+ </td>
+ </tr>
+ <tr>
+ <td>{{jsxref("Global_Objects/Proxy/handler/setPrototypeOf", "handler.setPrototypeOf()")}}</td>
+ <td>{{jsxref("Object.setPrototypeOf()")}}<br>
+ {{jsxref("Reflect.setPrototypeOf()")}}</td>
+ <td>如果 <code>target</code> 不可扩展,<code>prototype</code> 参数必须与<code>Object.getPrototypeOf(target)</code>的值相同。</td>
+ </tr>
+ <tr>
+ <td>{{jsxref("Global_Objects/Proxy/handler/isExtensible", "handler.isExtensible()")}}</td>
+ <td>{{jsxref("Object.isExtensible()")}}<br>
+ {{jsxref("Reflect.isExtensible()")}}</td>
+ <td><code>Object.isExtensible(proxy)</code> 必须返回和<code>Object.isExtensible(target)</code>一样的值。</td>
+ </tr>
+ <tr>
+ <td>{{jsxref("Global_Objects/Proxy/handler/preventExtensions", "handler.preventExtensions()")}}</td>
+ <td>{{jsxref("Object.preventExtensions()")}}<br>
+ {{jsxref("Reflect.preventExtensions()")}}</td>
+ <td> 如果<code>Object.isExtensible(proxy)</code> 值为 <code>false,Object.preventExtensions(proxy)</code> 只返回<code>true。</code></td>
+ </tr>
+ <tr>
+ <td>{{jsxref("Global_Objects/Proxy/handler/getOwnPropertyDescriptor", "handler.getOwnPropertyDescriptor()")}}</td>
+ <td>{{jsxref("Object.getOwnPropertyDescriptor()")}}<br>
+ {{jsxref("Reflect.getOwnPropertyDescriptor()")}}</td>
+ <td>
+ <ul>
+ <li><code>getOwnPropertyDescripton</code> 只能返回对象或者<code>undefined</code>.</li>
+ <li>A property cannot be reported as non-existent, if it exists as a non-configurable own property of the target object.</li>
+ <li>A property cannot be reported as non-existent, if it exists as an own property of the target object and the target object is not extensible.</li>
+ <li>A property cannot be reported as existent, if it does not exists as an own property of the target object and the target object is not extensible.</li>
+ <li>A property cannot be reported as non-configurable, if it does not exists as an own property of the target object or if it exists as a configurable own property of the target object.</li>
+ <li>The result of <code>Object.getOwnPropertyDescriptor(target)</code> can be applied to the target object using <code>Object.defineProperty</code> and will not throw an exception.</li>
+ </ul>
+ </td>
+ </tr>
+ <tr>
+ <td>{{jsxref("Global_Objects/Proxy/handler/defineProperty", "handler.defineProperty()")}}</td>
+ <td>{{jsxref("Object.defineProperty()")}}<br>
+ {{jsxref("Reflect.defineProperty()")}}</td>
+ <td>
+ <ul>
+ <li>A property cannot be added, if the target object is not extensible.</li>
+ <li>A property cannot be added as or modified to be non-configurable, if it does not exists as a non-configurable own property of the target object.</li>
+ <li>A property may not be non-configurable, if a corresponding configurable property of the target object exists.</li>
+ <li>If a property has a corresponding target object property then <code>Object.defineProperty(target, prop, descriptor)</code> will not throw an exception.</li>
+ <li>In strict mode, a <code>false</code> return value from the <code>defineProperty</code> handler will throw a {{jsxref("TypeError")}} exception.</li>
+ </ul>
+ </td>
+ </tr>
+ <tr>
+ <td>{{jsxref("Global_Objects/Proxy/handler/has", "handler.has()")}}</td>
+ <td>Property query: <code>foo in proxy</code><br>
+ Inherited property query: <code>foo in Object.create(proxy)</code><br>
+ {{jsxref("Reflect.has()")}}</td>
+ <td>
+ <ul>
+ <li>A property cannot be reported as non-existent, if it exists as a non-configurable own property of the target object.</li>
+ <li>A property cannot be reported as non-existent, if it exists as an own property of the target object and the target object is not extensible.</li>
+ </ul>
+ </td>
+ </tr>
+ <tr>
+ <td>{{jsxref("Global_Objects/Proxy/handler/get", "handler.get()")}}</td>
+ <td>Property access: <code>proxy[foo]</code>and <code>proxy.bar</code><br>
+ Inherited property access: <code>Object.create(proxy)[foo]</code><br>
+ {{jsxref("Reflect.get()")}}</td>
+ <td>
+ <ul>
+ <li>The value reported for a property must be the same as the value of the corresponding target object property if the target object property is a non-writable, non-configurable data property.</li>
+ <li>The value reported for a property must be undefined if the corresponding target object property is non-configurable accessor property that has undefined as its [[Get]] attribute.</li>
+ </ul>
+ </td>
+ </tr>
+ <tr>
+ <td>{{jsxref("Global_Objects/Proxy/handler/set", "handler.set()")}}</td>
+ <td>Property assignment: <code>proxy[foo] = bar</code> and <code>proxy.foo = bar</code><br>
+ Inherited property assignment: <code>Object.create(proxy)[foo] = bar</code><br>
+ {{jsxref("Reflect.set()")}}</td>
+ <td>
+ <ul>
+ <li>Cannot change the value of a property to be different from the value of the corresponding target object property if the corresponding target object property is a non-writable, non-configurable data property.</li>
+ <li>Cannot set the value of a property if the corresponding target object property is a non-configurable accessor property that has <code>undefined</code> as its [[Set]] attribute.</li>
+ <li>In strict mode, a <code>false</code> return value from the <code>set</code> handler will throw a {{jsxref("TypeError")}} exception.</li>
+ </ul>
+ </td>
+ </tr>
+ <tr>
+ <td>{{jsxref("Global_Objects/Proxy/handler/deleteProperty", "handler.deleteProperty()")}}</td>
+ <td>Property deletion: <code>delete proxy[foo]</code> and <code>delete proxy.foo</code><br>
+ {{jsxref("Reflect.deleteProperty()")}}</td>
+ <td>A property cannot be deleted, if it exists as a non-configurable own property of the target object.</td>
+ </tr>
+ <tr>
+ <td>{{jsxref("Global_Objects/Proxy/handler/enumerate", "handler.enumerate()")}}</td>
+ <td>Property enumeration / for...in: <code>for (var name in proxy) {...}</code><br>
+ {{jsxref("Reflect.enumerate()")}}</td>
+ <td>The <code>enumerate</code> method must return an object.</td>
+ </tr>
+ <tr>
+ <td>{{jsxref("Global_Objects/Proxy/handler/ownKeys", "handler.ownKeys()")}}</td>
+ <td>{{jsxref("Object.getOwnPropertyNames()")}}<br>
+ {{jsxref("Object.getOwnPropertySymbols()")}}<br>
+ {{jsxref("Object.keys()")}}<br>
+ {{jsxref("Reflect.ownKeys()")}}</td>
+ <td>
+ <ul>
+ <li>The result of <code>ownKeys</code> is a List.</li>
+ <li>The Type of each result List element is either {{jsxref("String")}} or {{jsxref("Symbol")}}.</li>
+ <li>The result List must contain the keys of all non-configurable own properties of the target object.</li>
+ <li>If the target object is not extensible, then the result List must contain all the keys of the own properties of the target object and no other values.</li>
+ </ul>
+ </td>
+ </tr>
+ <tr>
+ <td>{{jsxref("Global_Objects/Proxy/handler/apply", "handler.apply()")}}</td>
+ <td><code>proxy(..args)</code><br>
+ {{jsxref("Function.prototype.apply()")}} and {{jsxref("Function.prototype.call()")}}<br>
+ {{jsxref("Reflect.apply()")}}</td>
+ <td>There are no invariants for the <code>handler.apply</code> method.</td>
+ </tr>
+ <tr>
+ <td>{{jsxref("Global_Objects/Proxy/handler/construct", "handler.construct()")}}</td>
+ <td><code>new proxy(...args)</code><br>
+ {{jsxref("Reflect.construct()")}}</td>
+ <td>结果一定是一个<code>Object</code>。</td>
+ </tr>
+ </tbody>
+</table>
+
+<h2 id="撤销_Proxy">撤销 <code>Proxy</code></h2>
+
+<p>{{jsxref("Proxy.revocable()")}} 方法被用来创建可撤销的 <code>Proxy</code> 对象。这意味着 proxy 可以通过 <code>revoke</code> 函数来撤销,并且关闭代理。此后,代理上的任意的操作都会导致{{jsxref("TypeError")}}。</p>
+
+<pre class="brush: js notranslate">var revocable = Proxy.revocable({}, {
+ get: function(target, name) {
+ return "[[" + name + "]]";
+ }
+});
+var proxy = revocable.proxy;
+console.log(proxy.foo); // "[[foo]]"
+
+revocable.revoke();
+
+console.log(proxy.foo); // TypeError is thrown
+proxy.foo = 1 // TypeError again
+delete proxy.foo; // still TypeError
+typeof proxy // "object", typeof doesn't trigger any trap</pre>
+
+<h2 id="反射">反射</h2>
+
+<p>{{jsxref("Reflect")}} 是一个内置对象,它提供了可拦截 JavaScript 操作的方法。该方法和{{jsxref("Global_Objects/Proxy/handler","代理句柄")}}类似,但 <code>Reflect</code> 方法并不是一个函数对象。</p>
+
+<p><code>Reflect</code> 有助于将默认操作从处理程序转发到目标。</p>
+
+<p>以 {{jsxref("Reflect.has()")}} 为例,你可以将 <a href="/en-US/docs/Web/JavaScript/Reference/Operators/in"><code>in</code> 运算符</a>作为函数:</p>
+
+<pre class="brush: js notranslate">Reflect.has(Object, "assign"); // true
+</pre>
+
+<h3 id="更好的_apply_函数">更好的 <code>apply</code> 函数</h3>
+
+<p>在 ES5 中,我们通常使用 {{jsxref("Function.prototype.apply()")}} 方法调用一个具有给定 <code>this</code> 值和 <code>arguments</code> 数组(或<a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Guide/Indexed_collections#Working_with_array-like_objects">类数组对象</a>)的函数。</p>
+
+<pre class="brush: js notranslate">Function.prototype.apply.call(Math.floor, undefined, [1.75]);</pre>
+
+<p>使用 {{jsxref("Reflect.apply")}},这变得不那么冗长和容易理解:</p>
+
+<pre class="brush: js notranslate">Reflect.apply(Math.floor, undefined, [1.75]);
+// 1;
+
+Reflect.apply(String.fromCharCode, undefined, [104, 101, 108, 108, 111]);
+// "hello"
+
+Reflect.apply(RegExp.prototype.exec, /ab/, ['confabulation']).index;
+// 4
+
+Reflect.apply(''.charAt, 'ponies', [3]);
+// "i"</pre>
+
+<h3 id="检查属性定义是否成功">检查属性定义是否成功</h3>
+
+<p>使用 {{jsxref("Object.defineProperty")}},如果成功返回一个对象,否则抛出一个 {{jsxref("TypeError")}},你将使用 {{jsxref("Statements/try...catch","try...catch")}} 块来捕获定义属性时发生的任何错误。因为 {{jsxref("Reflect.defineProperty")}} 返回一个布尔值表示的成功状态,你可以在这里使用 {{jsxref("Statements/if...else","if...else")}} 块:</p>
+
+<pre class="brush: js notranslate">if (Reflect.defineProperty(target, property, attributes)) {
+ // success
+} else {
+ // failure
+}
+</pre>
+
+<p>{{Previous("Web/JavaScript/Guide/Iterators_and_Generators")}}</p>
diff --git a/files/zh-cn/web/javascript/guide/modules/index.html b/files/zh-cn/web/javascript/guide/modules/index.html
new file mode 100644
index 0000000000..1b0192666f
--- /dev/null
+++ b/files/zh-cn/web/javascript/guide/modules/index.html
@@ -0,0 +1,460 @@
+---
+title: JavaScript modules 模块
+slug: Web/JavaScript/Guide/Modules
+tags:
+ - JavaScript
+ - 导入
+ - 导出
+ - 指南
+ - 模块
+translation_of: Web/JavaScript/Guide/Modules
+---
+<div>{{jsSidebar("JavaScript Guide")}}{{Previous("Web/JavaScript/Guide/Meta_programming")}}</div>
+
+<p>这篇指南会给你入门 Javascript 模块的全部信息。</p>
+
+<h2 id="模块化的背景">模块化的背景</h2>
+
+<p>Javascript 程序本来很小——在早期,它们大多被用来执行独立的脚本任务,在你的 web 页面需要的地方提供一定交互,所以一般不需要多大的脚本。过了几年,我们现在有了运行大量 Javascript 脚本的复杂程序,还有一些被用在其他环境(例如 <a href="/en-US/docs/Glossary/Node.js">Node.js</a>)。</p>
+
+<p>因此,近年来,有必要开始考虑提供一种<u>将 JavaScript 程序拆分为可按需导入的单独模块</u>的机制。Node.js 已经提供这个能力很长时间了,还有很多的 Javascript 库和框架 已经开始了模块的使用(例如, <a href="https://en.wikipedia.org/wiki/CommonJS">CommonJS</a> 和基于 <a href="https://github.com/amdjs/amdjs-api/blob/master/AMD.md">AMD</a> 的其他模块系统 如 <a href="https://requirejs.org/">RequireJS</a>, 以及最新的 <a href="https://webpack.github.io/">Webpack</a> 和 <a href="https://babeljs.io/">Babel</a>)。</p>
+
+<p>好消息是,最新的浏览器开始原生支持模块功能了,这是本文要重点讲述的。这会是一个好事情 — 浏览器能够最优化加载模块,使它比使用库更有效率:使用库通常需要做额外的客户端处理。</p>
+
+<h2 id="浏览器支持">浏览器支持</h2>
+
+<p>使用JavaScript 模块依赖于<code>import</code>和 <code>export</code>,浏览器兼容性如下(绿色方框中的数字对应相应平台上支持该功能的发布版本):</p>
+
+<h3 id="import">import</h3>
+
+<p>{{Compat("javascript.statements.import")}}</p>
+
+<h3 id="export">export</h3>
+
+<p>{{Compat("javascript.statements.export")}}</p>
+
+<h2 id="介绍一个例子">介绍一个例子</h2>
+
+<p>为了演示模块的使用,我们创建了一个 <a href="https://github.com/mdn/js-examples/tree/master/modules">simple set of examples</a> ,你可以在Github上找到。这个例子演示了一个简单的模块的集合用来在web页面上创建了一个{{htmlelement("canvas")}} 标签,在canvas上绘制 (并记录有关的信息) 不同形状。</p>
+
+<p>这的确有点简单,但是保持足够简单能够清晰地演示模块。</p>
+
+<div class="blockIndicator note">
+<p><strong>Note</strong>: 如果你想去下载这个例子在本地运行,你需要通过本地web 服务器去运行。</p>
+</div>
+
+<h2 id="基本的示例文件的结构">基本的示例文件的结构</h2>
+
+<p>在我们的第一个例子 (see <a href="https://github.com/mdn/js-examples/tree/master/modules/basic-modules">basic-modules</a>) 文件结构如下:</p>
+
+<pre>index.html
+main.mjs
+modules/
+ canvas.mjs
+ square.mjs</pre>
+
+<div class="blockIndicator note">
+<p><strong>Note</strong>: 在这个指南的全部示例项目的文件结构是基本相同的; 需要熟悉上面的内容</p>
+</div>
+
+<p>modules 目录下的两个模块的描述如下:</p>
+
+<ul>
+ <li><code>canvas.mjs</code> — 包含与设置画布相关的功能:
+
+ <ul>
+ <li><code>create()</code> —在指定ID的包装器{{htmlelement("div")}}内创建指定<code>width</code> 和<code>height</code> 的画布,该ID本身附加在指定的父元素内。 返回包含画布的2D上下文和包装器ID的对象。</li>
+ <li><code>createReportList()</code> — 创建一个附加在指定包装器元素内的无序列表,该列表可用于将报告数据输出到。 返回列表的ID。</li>
+ </ul>
+ </li>
+ <li><code>square.mjs</code> — 包含:
+ <ul>
+ <li><code>name</code> — 包含字符串'square'的常量。</li>
+ <li><code>draw()</code> — 在指定画布上绘制一个正方形,具有指定的大小,位置和颜色。 返回包含正方形大小,位置和颜色的对象。</li>
+ <li><code>reportArea()</code> — 在给定长度的情况下,将正方形区域写入特定报告列表。</li>
+ <li><code>reportPerimeter()</code> — 在给定长度的情况下,将正方形的周长写入特定的报告列表。</li>
+ </ul>
+ </li>
+</ul>
+
+<div class="blockIndicator note">
+<p><strong>Note</strong>: 在原生JavaScript模块中, 扩展名 <code>.mjs</code> 非常重要,因为使用 MIME-type 为<code>javascript/esm</code> 来导入文件(其他的JavaScript 兼容 MIME-type 像 <code>application/javascript</code> 也可以), 它避免了严格的 MIME 类型检查错误,像 "The server responded with a non-JavaScript MIME type". 除此之外,  <code>.mjs</code> 的扩展名很明了(比如这个就是一个模块,而不是一个传统 JavaScript文件),还能够和其他工具互相适用. 看这个 <a href="https://v8.dev/features/modules#mjs">Google's note for further details</a>.</p>
+</div>
+
+<h2 id=".mjs_与_.js"><code>.mjs</code> 与 <code>.js</code></h2>
+
+<p>纵观此文,我们使用 <code>.js</code> 扩展名的模块文件,但在其它一些文章中,你可能会看到 <code>.mjs</code> 扩展名的使用。<a href="https://v8.dev/features/modules#mjs">V8推荐了这样的做法</a>,比如有下列理由:</p>
+
+<ul>
+ <li>比较清晰,这可以指出哪些文件是模块,哪些是常规的 JavaScript。</li>
+ <li>这能保证你的模块可以被运行时环境和构建工具识别,比如  <a href="https://nodejs.org/api/esm.html#esm_enabling">Node.js</a> 和 <a href="https://babeljs.io/docs/en/options#sourcetype">Babel</a>。</li>
+</ul>
+
+<p>但是我们决定继续使用 <code>.js</code> 扩展名,未来可能会更改。为了使模块可以在浏览器中正常地工作,你需要确保你的服务器能够正常地处理 <code>Content-Type</code> 头,其应该包含 Javascript 的MIME 类型  <code>text/javascript</code>。如果没有这么做,你可能会得到 一个严格 MIME 类型检查错误:“The server responded with a non-JavaScript MIME type (服务器返回了非 JavaScript MIME 类型)”,并且浏览器会拒绝执行相应的 JavaScript 代码。多数服务器可以正确地处理 <code>.js</code> 文件的类型,但是 <code>.mjs</code> 还不行。已经可以正常响应 <code>.mjs</code> 的服务器有 <a href="https://pages.github.com/">GitHub 页面</a> 和 Node.js 的 <code><a href="https://github.com/http-party/http-server#readme">http-server</a></code>。</p>
+
+<p> 如果你已经在使用相应的环境了,那么一切正常。或者如果你还没有,但你知道你在做什么(比如你可以配置服务器以为 <code>.mjs</code> 设置正确的 <code>Content-Type</code>)。但如果你不能控制提供服务,或者用于公开文件发布的服务器,这可能会导致混乱。</p>
+
+<p>为了学习和保证代码的可移植的目的,我们建议使用 <code>.js</code>。</p>
+
+<p>如果你认为使用 <code>.mjs</code> 仅用于模块带来的清晰性非常重要,但不想引入上面描述的相应问题,你可以仅在开发过程中使用 <code>.mjs</code>,而在构建过程中将其转换为 <code>.js</code>。</p>
+
+<p>另注意:</p>
+
+<ul>
+ <li>一些工具不支持 <code>.mjs</code>,比如 <a href="https://www.typescriptlang.org/">TypeScript</a>。</li>
+ <li><code>&lt;script type="module"&gt;</code> 属性用于指示引入的模块,你会在下面看到。</li>
+</ul>
+
+<h2 id="导出模块的功能">导出模块的功能</h2>
+
+<p>为了获得模块的功能要做的第一件事是把它们导出来。使用 <code><a href="/en-US/docs/Web/JavaScript/Reference/Statements/export">export</a></code> 语句来完成。</p>
+
+<p>最简单的方法是把它(指上面的export语句)放到你想要导出的项前面,比如:</p>
+
+<pre class="brush: js">export const name = 'square';
+
+export function draw(ctx, length, x, y, color) {
+ ctx.fillStyle = color;
+ ctx.fillRect(x, y, length, length);
+
+ return {
+ length: length,
+ x: x,
+ y: y,
+ color: color
+ };
+}</pre>
+
+<p>你能够导出函数,<code>var</code><font face="Arial, x-locale-body, sans-serif"><span style="background-color: #ffffff;">,</span></font><code>let</code><font face="Arial, x-locale-body, sans-serif"><span style="background-color: #ffffff;">,</span></font><code>const</code>, 和等会会看到的类。export要放在最外层;比如你不能够在函数内使用<code>export</code>。</p>
+
+<p>一个更方便的方法导出所有你想要导出的模块的方法是在模块文件的末尾使用一个export 语句, 语句是用花括号括起来的用逗号分割的列表。比如:</p>
+
+<pre class="brush: js">export { name, draw, reportArea, reportPerimeter };</pre>
+
+<h2 id="导入功能到你的脚本">导入功能到你的脚本</h2>
+
+<p>你想在模块外面使用一些功能,那你就需要导入他们才能使用。最简单的就像下面这样的:</p>
+
+<pre>import { name, draw, reportArea, reportPerimeter } from '/js-examples/modules/basic-modules/modules/square.mjs';</pre>
+
+<p>使用 <code><a href="/en-US/docs/Web/JavaScript/Reference/Statements/import">import</a></code> 语句,然后你被花括号包围的用逗号分隔的你想导入的功能列表,然后是关键字from,然后是模块文件的路径。模块文件的路径是相对于站点根目录的相对路径,对于我们的<code>basic-modules</code> 应该是<code> /js-examples/modules/basic-modules</code>。</p>
+
+<p>当然,我们写的路径有一点不同---我们使用点语法意味 “当前路径”,跟随着包含我们想要找的文件的路径。这比每次都要写下整个相对路径要好得多,因为它更短,使得URL 可移植 ---如果在站点层中你把它移动到不同的路径下面仍然能够工作。<span style='background-color: #fff3d4; color: #333333; display: inline !important; float: none; font-family: x-locale-heading-primary,zillaslab,Palatino,"Palatino Linotype",x-locale-heading-secondary,serif; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal;'>(修订版 1889482)</span></p>
+
+<p>那么看看例子吧:</p>
+
+<pre>/js/examples/modules/basic-modules/modules/square.mjs</pre>
+
+<p>变成了</p>
+
+<pre>./modules/square.mjs</pre>
+
+<p>你可以在<code><a href="https://github.com/mdn/js-examples/blob/master/modules/basic-modules/main.js">main.mjs</a></code>中看到这些。</p>
+
+<div class="blockIndicator note">
+<p><strong>Note</strong>:在一些模块系统中你可以忽略文件扩展名(比如<code>'/model/squre'</code> .这在原生JavaScript 模块系统中不工作。<s>此外,记住你需要包含最前面的正斜杠。  </s> <span style='background-color: #fff3d4; color: #333333; display: inline !important; float: none; font-family: x-locale-heading-primary,zillaslab,Palatino,"Palatino Linotype",x-locale-heading-secondary,serif; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal;'>(修订版 1889482)</span></p>
+</div>
+
+<p>因为你导入了这些功能到你的脚本文件,你可以像定义在相同的文件中的一样去使用它。下面展示的是在 <code>main.mjs</code> 中的import 语句下面的内容。</p>
+
+<pre class="brush: js">let myCanvas = create('myCanvas', document.body, 480, 320);
+let reportList = createReportList(myCanvas.id);
+
+let square1 = draw(myCanvas.ctx, 50, 50, 100, 'blue');
+reportArea(square1.length, reportList);
+reportPerimeter(square1.length, reportList);
+</pre>
+
+<h2 id="应用模块到你的HTML">应用模块到你的HTML</h2>
+
+<p>现在我们只需要将main.mjs模块应用到我们的HTML页面。 这与我们将常规脚本应用于页面的方式非常相似,但有一些显着的差异。</p>
+
+<p>首先,你需要把 <code>type="module"</code> 放到 {{htmlelement("script")}} 标签中, 来声明这个脚本是一个模块:</p>
+
+<pre>&lt;script type="module" src="main.mjs"&gt;&lt;/script&gt;</pre>
+
+<p>你导入模块功能的脚本基本是作为顶级模块。 如果省略它,Firefox就会给出错误“SyntaxError: import declarations may only appear at top level of a module。</p>
+
+<p>你只能在模块内部使用 <code>import</code> 和<code>export</code> 语句 ;不是普通脚本文件。</p>
+
+<div class="blockIndicator note">
+<p><strong>Note</strong>: 您还可以将模块导入内部脚本,只要包含 <code>type="module"</code>,例如 <code>&lt;script type="module"&gt; //include script here &lt;/script&gt;</code>.</p>
+</div>
+
+<h2 id="其他模块与标准脚本的不同">其他模块与标准脚本的不同</h2>
+
+<ul>
+ <li>你需要注意本地测试 —  如果你通过本地加载Html 文件 (比如一个 <code>file://</code> 路径的文件), 你将会遇到 CORS 错误,因为Javascript 模块安全性需要。你需要通过一个服务器来测试。</li>
+ <li>另请注意,您可能会从模块内部定义的脚本部分获得不同的行为,而不是标准脚本。 这是因为模块自动使用严格模式。</li>
+ <li>加载一个模块脚本时不需要使用 <code>defer</code> 属性 (see <a href="/en-US/docs/Web/HTML/Element/script#Attributes"><code>&lt;script&gt;</code> attributes</a>) 模块会自动延迟加载。</li>
+ <li>最后一个但不是不重要,你需要明白模块功能导入到单独的脚本文件的范围 — 他们无法在全局获得。因此,你只能在导入这些功能的脚本文件中使用他们,你也无法通过Javascript console 中获取到他们,比如,在DevTools 中你仍然能够获取到语法错误,但是你可能无法像你想的那样使用一些debug 技术 </li>
+</ul>
+
+<h2 id="默认导出_versus_命名导出">默认导出 versus 命名导出</h2>
+
+<p>到目前为止我们导出的功能都是由<strong>named exports</strong> 组成— 每个项目(无论是函数,常量等)在导出时都由其名称引用,并且该名称也用于在导入时引用它。</p>
+
+<p>还有一种导出类型叫做 <strong>default export</strong> —这样可以很容易地使模块提供默认功能,并且还可以帮助JavaScript模块与现有的CommonJS和AMD模块系统进行互操作(正如<a href="https://hacks.mozilla.org/2015/08/es6-in-depth-modules/">ES6 In Depth: Modules</a> by Jason Orendorff的模块中所解释的那样;搜索“默认导出”“)。</p>
+
+<p>看个例子来解释它如何工作。在我们的基本模块<code>square.mjs</code>中,您可以找到一个名为<code>randomSquare()</code>的函数,它创建一个具有随机颜色,大小和位置的正方形。我们想作为默认导出,所以在文件的底部我们这样写 :</p>
+
+<pre class="brush: js">export default randomSquare;</pre>
+
+<p>注意,不要大括号。</p>
+
+<p>我们可以把 <code>export default</code> 放到函数前面,定义它为一个匿名函数,像这样:</p>
+
+<pre class="brush: js">export default function(ctx) {
+ ...
+}</pre>
+
+<p>在我们的<code>main.mjs</code> 文件中,我们使用以下行导入默认函数:</p>
+
+<pre class="brush: js">import randomSquare from './modules/square.mjs';</pre>
+
+<p>同样,没有大括号,因为每个模块只允许有一个默认导出, 我们知道 <code>randomSquare</code> 就是需要的那个。上面的那一行相当于下面的缩写:</p>
+
+<pre class="brush: js">import {default as randomSquare} from './modules/square.mjs';</pre>
+
+<div class="blockIndicator note">
+<p><strong>Note</strong>: 重命名导出项的as语法在下面的{{anch("Renaming imports and exports")}}部分中进行了说明。</p>
+</div>
+
+<h2 id="避免命名冲突">避免命名冲突</h2>
+
+<p>到目前为止,我们的canvas 图形绘制模块看起来工作的很好。但是如果我们添加一个绘制其他形状的比如圆形或者矩形的模块会发生什么?这些形状可能会有相关的函数比如 <code>draw()</code>、<code>reportArea()</code>,等等;如果我们用相同的名字导入不同的函数到顶级模块文件中,我们会收到冲突和错误。</p>
+
+<p>幸运的是,有很多方法来避免。我们将会在下一个节看到。</p>
+
+<h2 id="重命名导出与导入">重命名导出与导入</h2>
+
+<p>在你的 <code>import</code> 和 <code>export</code> 语句的大括号中,可以使用 <code>as</code> 关键字跟一个新的名字,来改变你在顶级模块中将要使用的功能的标识名字。因此,例如,以下两者都会做同样的工作,尽管方式略有不同:</p>
+
+<pre class="brush: js">// inside module.mjs
+export {
+ function1 as newFunctionName,
+ function2 as anotherNewFunctionName
+};
+
+// inside main.mjs
+import { newFunctionName, anotherNewFunctionName } from '/modules/module.mjs';</pre>
+
+<pre class="brush: js">// inside module.mjs
+export { function1, function2 };
+
+// inside main.mjs
+import { function1 as newFunctionName,
+ function2 as anotherNewFunctionName } from '/modules/module.mjs';</pre>
+
+<p>让我们看一个真实的例子。在我们的<a href="https://github.com/mdn/js-examples/tree/master/modules/renaming">重命名</a>目录中,您将看到与上一个示例中相同的模块系统,除了我们添加了<code>circle.mjs</code>和<code>triangle.mjs</code>模块以绘制和报告圆和三角形。</p>
+
+<p>在每个模块中,我们都有<code>export</code> 相同名称的功能,因此每个模块底部都有相同的导出语句:</p>
+
+<pre class="brush: js">export { name, draw, reportArea, reportPerimeter };</pre>
+
+<p>将它们导入<code>main.mjs</code>时,如果我们尝试使用</p>
+
+<pre class="brush: js">import { name, draw, reportArea, reportPerimeter } from './modules/square.mjs';
+import { name, draw, reportArea, reportPerimeter } from './modules/circle.mjs';
+import { name, draw, reportArea, reportPerimeter } from './modules/triangle.mjs';</pre>
+
+<p>浏览器会抛出一个错误,例如“SyntaxError: redeclaration of import name”(Firefox)。</p>
+
+<p>相反,我们需要重命名导入,使它们是唯一的:</p>
+
+<pre class="brush: js">import { name as squareName,
+ draw as drawSquare,
+ reportArea as reportSquareArea,
+ reportPerimeter as reportSquarePerimeter } from './modules/square.mjs';
+
+import { name as circleName,
+ draw as drawCircle,
+ reportArea as reportCircleArea,
+ reportPerimeter as reportCirclePerimeter } from './modules/circle.mjs';
+
+import { name as triangleName,
+ draw as drawTriangle,
+ reportArea as reportTriangleArea,
+ reportPerimeter as reportTrianglePerimeter } from './modules/triangle.mjs';</pre>
+
+<p>请注意,您可以在模块文件中解决问题,例如</p>
+
+<pre class="brush: js">// in square.mjs
+export { name as squareName,
+ draw as drawSquare,
+ reportArea as reportSquareArea,
+ reportPerimeter as reportSquarePerimeter };</pre>
+
+<pre class="brush: js">// in main.mjs
+import { squareName, drawSquare, reportSquareArea, reportSquarePerimeter } from '/js-examples/modules/renaming/modules/square.mjs';</pre>
+
+<p>它也会起作用。 你使用什么样的风格取决于你,但是单独保留模块代码并在导入中进行更改可能更有意义。 当您从没有任何控制权的第三方模块导入时,这尤其有意义。</p>
+
+<h2 id="创建模块对象">创建模块对象</h2>
+
+<p>上面的方法工作的挺好,但是有一点点混乱、亢长。一个更好的解决方是,导入每一个模块功能到一个模块功能对象上。可以使用以下语法形式:</p>
+
+<pre class="brush: js">import * as Module from '/modules/module.mjs';</pre>
+
+<p>这将获取<code>module.mjs</code>中所有可用的导出,并使它们可以作为对象模块的成员使用,从而有效地为其提供自己的命名空间。 例如:</p>
+
+<pre class="brush: js">Module.function1()
+Module.function2()
+etc.</pre>
+
+<p>再次,让我们看一个真实的例子。如果您转到我们的<a href="https://github.com/mdn/js-examples/tree/master/modules/module-objects">module-objects</a>目录,您将再次看到相同的示例,但利用上述的新语法进行重写。在模块中,导出都是以下简单形式:</p>
+
+<pre class="brush: js">export { name, draw, reportArea, reportPerimeter };</pre>
+
+<p>另一方面,导入看起来像这样:</p>
+
+<pre class="brush: js">import * as Canvas from './modules/canvas.mjs';
+
+import * as Square from '/./modules/square.mjs';
+import * as Circle from './modules/circle.mjs';
+import * as Triangle from './modules/triangle.mjs';</pre>
+
+<p>在每种情况下,您现在可以访问指定对象名称下面的模块导入</p>
+
+<pre class="brush: js">let square1 = Square.draw(myCanvas.ctx, 50, 50, 100, 'blue');
+Square.reportArea(square1.length, reportList);
+Square.reportPerimeter(square1.length, reportList);</pre>
+
+<p>因此,您现在可以像以前一样编写代码(只要您在需要时包含对象名称),并且导入更加整洁。</p>
+
+<h2 id="模块与类(class)">模块与类(class)</h2>
+
+<p>正如我们之前提到的那样,您还可以导出和导入类; 这是避免代码冲突的另一种选择,如果您已经以面向对象的方式编写了模块代码,那么它尤其有用。</p>
+
+<p>您可以在我们的<a href="https://github.com/mdn/js-examples/tree/master/modules/classes">classes</a> 目录中看到使用ES类重写的形状绘制模块的示例。 例如,<code><a href="https://github.com/mdn/js-examples/blob/master/modules/classes/modules/square.js">square.mjs</a></code> 文件现在包含单个类中的所有功能:</p>
+
+<pre class="brush: js">class Square {
+ constructor(ctx, listId, length, x, y, color) {
+ ...
+ }
+
+ draw() {
+ ...
+ }
+
+ ...
+}</pre>
+
+<p>然后我们导出:</p>
+
+<pre class="brush: js">export { Square };</pre>
+
+<p>在<code><a href="https://github.com/mdn/js-examples/blob/master/modules/classes/main.js">main.mjs</a></code>中,我们像这样导入它:</p>
+
+<pre class="brush: js">import { Square } from './modules/square.mjs';</pre>
+
+<p>然后使用该类绘制我们的方块:</p>
+
+<pre class="brush: js">let square1 = new Square(myCanvas.ctx, myCanvas.listId, 50, 50, 100, 'blue');
+square1.draw();
+square1.reportArea();
+square1.reportPerimeter();</pre>
+
+<h2 id="合并模块">合并模块</h2>
+
+<p>有时你会想要将模块聚合在一起。 您可能有多个级别的依赖项,您希望简化事物,将多个子模块组合到一个父模块中。 这可以使用父模块中以下表单的导出语法:</p>
+
+<pre class="brush: js">export * from 'x.mjs'
+export { name } from 'x.mjs'</pre>
+
+<div class="blockIndicator note">
+<p><strong>Note</strong>: 这实际上是导入后跟导出的简写,即“我导入模块<code>x.mjs</code>,然后重新导出部分或全部导出”。</p>
+</div>
+
+<p>有关示例,请参阅我们的<a href="https://github.com/mdn/js-examples/tree/master/modules/module-aggregation">module-aggregation</a>。 在这个例子中(基于我们之前的类示例),我们有一个名为<code>shapes.mjs</code>的额外模块,它将<code>circle.mjs</code>,<code>square.mjs</code>和<code>riangle.mjs</code>中的所有功能聚合在一起。 我们还将子模块移动到名为shapes的modules目录中的子目录中。 所以模块结构现在是这样的:</p>
+
+<pre>modules/
+ canvas.mjs
+ shapes.mjs
+ shapes/
+ circle.mjs
+ square.mjs
+ triangle.mjs</pre>
+
+<p>在每个子模块中,输出具有相同的形式,例如,</p>
+
+<pre class="brush: js">export { Square };</pre>
+
+<p>接下来是聚合部分。 在<code><a href="https://github.com/mdn/js-examples/blob/master/modules/module-aggregation/modules/shapes.js">shapes.mjs</a></code>里面,我们包括以下几行:</p>
+
+<pre class="brush: js">export { Square } from '/js-examples/modules/module-aggregation/modules/shapes/square.mjs';
+export { Triangle } from '/js-examples/modules/module-aggregation/modules/shapes/triangle.mjs';
+export { Circle } from '/js-examples/modules/module-aggregation/modules/shapes/circle.mjs';</pre>
+
+<p>它们从各个子模块中获取导出,并有效地从<code>shapes.mjs</code>模块中获取它们。</p>
+
+<div class="blockIndicator note">
+<p><strong>Note</strong>: 即使<code>shapes.mjs</code>文件位于modules目录中,我们仍然需要相对于模块根目录编写这些URL,因此需要<code>/modules/</code>。 这是使用JavaScript模块时混淆的常见原因。</p>
+</div>
+
+<div class="blockIndicator note">
+<p><strong>Note</strong>: <code>shapes.mjs</code>中引用的导出基本上通过文件重定向,并且实际上并不存在,因此您将无法在同一文件中编写任何有用的相关代码。</p>
+</div>
+
+<p>所以现在在<code>main.mjs</code> 文件中,我们可以通过替换来访问所有三个模块类</p>
+
+<pre class="brush: js">import { Square } from './modules/square.mjs';
+import { Circle } from './modules/circle.mjs';
+import { Triangle } from './modules/triangle.mjs';</pre>
+
+<p>使用以下单行:</p>
+
+<pre class="brush: js">import { Square, Circle, Triangle } from './modules/shapes.mjs';</pre>
+
+<h2 id="动态加载模块">动态加载模块</h2>
+
+<p>浏览器中可用的JavaScript模块功能的最新部分是动态模块加载。 这允许您仅在需要时动态加载模块,而不必预先加载所有模块。 这有一些明显的性能优势; 让我们继续阅读,看看它是如何工作的。</p>
+
+<p>这个新功能允许您将<code>import()</code>作为函数调用,将其作为参数传递给模块的路径。 它返回一个 <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise">promise</a>,它用一个模块对象来实现(参见{{anch("Creating a module object")}}),让你可以访问该对象的导出,例如</p>
+
+<pre class="brush: js">import('/modules/myModule.mjs')
+ .then((module) =&gt; {
+ // Do something with the module.
+ });</pre>
+
+<p>我们来看一个例子。 在<a href="https://github.com/mdn/js-examples/tree/master/modules/dynamic-module-imports">dynamic-module-imports</a> 目录中,我们有另一个基于类示例的示例。 但是这次我们在示例加载时没有在画布上绘制任何东西。 相反,我们包括三个按钮 - “圆形”,“方形”和“三角形” - 按下时,动态加载所需的模块,然后使用它来绘制相关的形状。</p>
+
+<p>在这个例子中,我们只对<a href="https://github.com/mdn/js-examples/blob/master/modules/dynamic-module-imports/index.html">index.html</a> 和<a href="https://github.com/mdn/js-examples/blob/master/modules/dynamic-module-imports/main.js">main.mjs</a>文件进行了更改 - 模块导出保持与以前相同。</p>
+
+<p>在<code>main.mjs</code>中,我们使用<code><a href="/en-US/docs/Web/API/Document/querySelector">document.querySelector()</a></code>调用获取了对每个按钮的引用,例如:</p>
+
+<pre class="brush: js">let squareBtn = document.querySelector('.square');</pre>
+
+<p>然后,我们为每个按钮附加一个事件监听器,以便在按下时,相关模块被动态加载并用于绘制形状:</p>
+
+<pre class="brush: js">squareBtn.addEventListener('click', () =&gt; {
+ import('/js-examples/modules/dynamic-module-imports/modules/square.mjs').then((Module) =&gt; {
+ let square1 = new Module.Square(myCanvas.ctx, myCanvas.listId, 50, 50, 100, 'blue');
+ square1.draw();
+ square1.reportArea();
+ square1.reportPerimeter();
+ })
+});</pre>
+
+<p>请注意,由于promise履行会返回一个模块对象,因此该类成为对象的子特征,因此我们现在需要使用 <code>Module</code>访问构造函数。 在它之前,例如 <code>Module.Square( ... )</code>。</p>
+
+<h2 id="故障排除">故障排除</h2>
+
+<p>如果为了你的模块有问题,这里有一些提示有可能帮助到你。如果你发现更多的内容欢迎添加进来!</p>
+
+<ul>
+ <li>在前面已经提到了,在这里再重申一次: <code>.mjs</code> 后缀的文件需要以 MIME-type 为 <code>javascript/esm</code> 来加载(或者其他的JavaScript 兼容的 MIME-type ,比如 <code>application/javascript</code>), 否则,你会一个严格的 MIME 类型检查错误,像是这样的 "The server responded with a non-JavaScript MIME type".</li>
+ <li>如果你尝试用本地文件加载HTML 文件 (i.e. with a <code>file://</code> URL), 由于JavaScript 模块的安全性要求,你会遇到CORS 错误。你需要通过服务器来做你的测试。GitHub pages is ideal as it also serves <code>.mjs</code> files with the correct MIME type.</li>
+ <li>因为<code>.mjs</code> 是一个相当新的文件后缀, 一些操作系统可能无法识别,或者尝试把它替换成别的。比如,我们发现macOS悄悄地该我们的 <code>.mjs</code> 后缀的文件后面添加上 <code>.js</code>  然后自动隐藏这个后缀。所以我们的文件实际上都是 <code>x.mjs.js</code>. 当我们关闭自动隐藏文件后缀名,让它去接受认可 <code>.mjs</code>。问题解决。</li>
+</ul>
+
+<h2 id="参见">参见</h2>
+
+<ul>
+ <li><a href="https://developers.google.com/web/fundamentals/primers/modules#mjs">Using JavaScript modules on the web</a>, by Addy Osmani and Mathias Bynens</li>
+ <li><a href="https://hacks.mozilla.org/2018/03/es-modules-a-cartoon-deep-dive/">ES modules: A cartoon deep-dive</a>, Hacks blog post by Lin Clark</li>
+ <li><a href="https://hacks.mozilla.org/2015/08/es6-in-depth-modules/">ES6 in Depth: Modules</a>, Hacks blog post by Jason Orendorff</li>
+ <li>Axel Rauschmayer's book <a href="http://exploringjs.com/es6/ch_modules.html">Exploring JS: Modules</a></li>
+</ul>
+
+<p>{{Previous("Web/JavaScript/Guide/Meta_programming")}}</p>
diff --git a/files/zh-cn/web/javascript/guide/numbers_and_dates/index.html b/files/zh-cn/web/javascript/guide/numbers_and_dates/index.html
new file mode 100644
index 0000000000..392c659766
--- /dev/null
+++ b/files/zh-cn/web/javascript/guide/numbers_and_dates/index.html
@@ -0,0 +1,407 @@
+---
+title: 数字和日期
+slug: Web/JavaScript/Guide/Numbers_and_dates
+tags:
+ - JavaScript
+ - 指南
+translation_of: Web/JavaScript/Guide/Numbers_and_dates
+---
+<div>{{jsSidebar("JavaScript Guide")}} {{PreviousNext("Web/JavaScript/Guide/Expressions_and_Operators", "Web/JavaScript/Guide/Text_formatting")}}</div>
+
+<div>本章节介绍了在JavaScript中使用数字和日期来处理和执行计算的概念,对象和函数。</div>
+
+<p class="summary">本章节介绍如何掌握Javascript里的数字和日期类型</p>
+
+<h2 id="数字">数字</h2>
+
+<p>在 JavaScript 里面,数字均为双精度浮点类型(<a href="https://en.wikipedia.org/wiki/Double-precision_floating-point_format">double-precision 64-bit binary format IEEE 754</a>),即一个介于±2<sup>−1023</sup>和±2<sup>+1024</sup>之间的数字,或约为±10<sup>−308</sup>到±10<sup>+308</sup>,数字精度为53位。整数数值仅在±(2<sup>53 -</sup> 1)的范围内可以表示准确。</p>
+
+<p>除了能够表示浮点数,数字类型也还能表示三种符号值: <code>+</code>{{jsxref("Infinity")}}(正无穷)、<code>-</code>{{jsxref("Infinity")}}(负无穷)和 {{jsxref("NaN")}} (not-a-number,非数字)。</p>
+
+<p>JavaScript最近添加了 {{jsxref("BigInt")}} 的支持,能够用于表示极大的数字。使用 BigInt 的时候有一些注意事项,例如,你不能让 BigInt 和 {{jsxref("Number")}} 直接进行运算,你也不能用 {{jsxref("Math")}} 对象去操作 BigInt 数字。</p>
+
+<p>请参见Javascript指南中的 <a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Data_structures">JavaScript 数据类型和数据结构</a> ,了解其他更多的基本类型。</p>
+
+<p>您可以使用四种数字进制:十进制,二进制,八进制和十六进制。</p>
+
+<h3 id="十进制数字Decimal_numbers">十进制数字(Decimal numbers)</h3>
+
+<pre class="brush: js notranslate">1234567890
+42
+// 以零开头的数字的注意事项:
+0888 // 888 将被当做十进制处理
+0777 // 在非严格格式下会被当做八进制处理 (用十进制表示就是511)
+</pre>
+
+<p>请注意,十进制可以以0开头,后面接其他十进制数字,但是假如下一个接的十进制数字小于8,那么该数字将会被当做八进制处理。</p>
+
+<h3 id="二进制数字Binary_numbers">二进制数字(Binary numbers)</h3>
+
+<p>二进制数字语法是以零为开头,后面接一个小写或大写的拉丁文字母B(<code>0b或者是0B</code>)。 假如0b后面的数字不是0或者1,那么就会提示这样的语法错误( <code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/SyntaxError">SyntaxError</a>):</code> "Missing binary digits after 0b(0b之后缺失二有效的二进制数据)"。</p>
+
+<pre class="brush: js notranslate">var FLT_SIGNBIT = 0b10000000000000000000000000000000; // 2147483648
+var FLT_EXPONENT = 0b01111111100000000000000000000000; // 2139095040
+var FLT_MANTISSA = 0B00000000011111111111111111111111; // 8388607</pre>
+
+<h3 id="八进制数字Octal_numbers">八进制数字(Octal numbers)</h3>
+
+<p>八进制数字语法是以0为开头的。假如0后面的数字不在0到7的范围内,该数字将会被转换成十进制数字。</p>
+
+<pre class="brush: js notranslate">var n = 0755; // 493
+var m = 0644; // 420
+</pre>
+
+<p>在ECMAScript 5 严格模式下禁止使用八进制语法。八进制语法并不是ECMAScript 5规范的一部分,但是通过在八进制数字添加一个前缀0就可以被所有的浏览器支持:0644 === 420 而且 "\045" === "%"。在ECMAScript 6中使用八进制数字是需要给一个数字添加前缀"0o"。</p>
+
+<pre class="brush: js notranslate">var a = 0o10; // ES6 :八进制</pre>
+
+<h3 id="十六进制Hexadecimal_numbers">十六进制(Hexadecimal numbers)</h3>
+
+<p>十六进制数字语法是以零为开头,后面接一个小写或大写的拉丁文字母X(<code>0x或者是0X</code>)。假如<code>0x</code>后面的数字超出规定范围(0123456789ABCDEF),那么就会提示这样的语法错误(<code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/SyntaxError">SyntaxError</a>):</code>"Identifier starts immediately after numeric literal".</p>
+
+<pre class="brush: js notranslate">0xFFFFFFFFFFFFFFFFF // 295147905179352830000
+0x123456789ABCDEF // 81985529216486900
+0XA // 10
+</pre>
+
+<h3 id="指数形式Exponentiation">指数形式(Exponentiation)</h3>
+
+<pre class="brush: js notranslate">1E3 // 1000
+2e6 // 2000000
+0.1e2 // 10
+</pre>
+
+<h2 id="数字对象"><font face="Consolas, Liberation Mono, Courier, monospace"><code>数字对象</code></font></h2>
+
+<p>内置的{{jsxref("Number")}}对象有一些有关数字的常量属性,如最大值、不是一个数字和无穷大的。你不能改变这些属性,但可以按下边的方式使用它们:</p>
+
+<pre class="brush: js notranslate">var biggestNum = Number.MAX_VALUE;
+var smallestNum = Number.MIN_VALUE;
+var infiniteNum = Number.POSITIVE_INFINITY;
+var negInfiniteNum = Number.NEGATIVE_INFINITY;
+var notANum = Number.NaN;
+</pre>
+
+<p>你永远只用从Number对象引用上边显示的属性,而不是你自己创建的Number对象的属性。</p>
+
+<p>下面的表格汇总了数字对象的属性:</p>
+
+<p><strong>数字的属性</strong></p>
+
+<table>
+ <thead>
+ <tr>
+ <th scope="col">属性</th>
+ <th scope="col">描述</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>{{jsxref("Number.MAX_VALUE")}}</td>
+ <td>可表示的最大值</td>
+ </tr>
+ <tr>
+ <td>{{jsxref("Number.MIN_VALUE")}}</td>
+ <td>可表示的最小值</td>
+ </tr>
+ <tr>
+ <td>{{jsxref("Number.NaN")}}</td>
+ <td>特指”非数字“</td>
+ </tr>
+ <tr>
+ <td>{{jsxref("Number.NEGATIVE_INFINITY")}}</td>
+ <td>特指“负无穷”;在溢出时返回</td>
+ </tr>
+ <tr>
+ <td>{{jsxref("Number.POSITIVE_INFINITY")}}</td>
+ <td>特指“正无穷”;在溢出时返回</td>
+ </tr>
+ <tr>
+ <td>{{jsxref("Number.EPSILON")}}</td>
+ <td>
+ <p>表示1和比最接近1且大于1的最小{{jsxref("Number")}}之间的差别</p>
+ </td>
+ </tr>
+ <tr>
+ <td>{{jsxref("Number.MIN_SAFE_INTEGER")}}</td>
+ <td>JavaScript最小安全整数.</td>
+ </tr>
+ <tr>
+ <td>{{jsxref("Number.MAX_SAFE_INTEGER")}}</td>
+ <td>JavaScript最大安全整数.</td>
+ </tr>
+ </tbody>
+</table>
+
+<table>
+ <caption>数字的方法</caption>
+ <thead>
+ <tr>
+ <th>方法</th>
+ <th>描述</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>{{jsxref("Number.parseFloat()")}}</td>
+ <td>把字符串参数解析成浮点数,<br>
+ 和全局方法 {{jsxref("parseFloat", "parseFloat()")}} 作用一致.</td>
+ </tr>
+ <tr>
+ <td>{{jsxref("Number.parseInt()")}}</td>
+ <td>
+ <p>把字符串解析成特定基数对应的整型数字,和全局方法 {{jsxref("parseInt", "parseInt()")}} 作用一致.</p>
+ </td>
+ </tr>
+ <tr>
+ <td>{{jsxref("Number.isFinite()")}}</td>
+ <td>判断传递的值是否为有限数字。</td>
+ </tr>
+ <tr>
+ <td>{{jsxref("Number.isInteger()")}}</td>
+ <td>判断传递的值是否为整数。</td>
+ </tr>
+ <tr>
+ <td>{{jsxref("Number.isNaN()")}}</td>
+ <td>判断传递的值是否为 {{jsxref("Global_Objects/NaN", "NaN")}}. More robust version of the original global {{jsxref("Global_Objects/isNaN", "isNaN()")}}.</td>
+ </tr>
+ <tr>
+ <td>{{jsxref("Number.isSafeInteger()")}}</td>
+ <td>判断传递的值是否为安全整数。</td>
+ </tr>
+ </tbody>
+</table>
+
+<p>数字的类型提供了不同格式的方法以从数字对象中检索信息。以下表格总结了 <code>数字类型原型上的方法。</code></p>
+
+<table>
+ <caption>数字类型原型上的一些方法</caption>
+ <thead>
+ <tr>
+ <th scope="col">方法</th>
+ <th scope="col">描述</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>{{jsxref("Number.toExponential", "toExponential()")}}</td>
+ <td>返回一个数字的指数形式的字符串,形如:1.23e+2</td>
+ </tr>
+ <tr>
+ <td>{{jsxref("Number.toFixed", "toFixed()")}}</td>
+ <td>
+ <p>返回指定小数位数的表示形式,</p>
+
+ <p>var a=123,b=a.toFixed(2)//b="123.00"</p>
+ </td>
+ </tr>
+ <tr>
+ <td>{{jsxref("Number.toPrecision", "toPrecision()")}}</td>
+ <td>
+ <p>返回一个指定精度的数字。如下例子中,a=123中,3会由于精度限制消失</p>
+
+ <p>var a=123,b=a.toPrecision(2)//b="1.2e+2"</p>
+ </td>
+ </tr>
+ </tbody>
+</table>
+
+<h2 id="数学对象(Math)"><font face="consolas, Liberation Mono, courier, monospace">数学对象(Math)</font></h2>
+
+<p>对于内置的{{jsxref("Math")}}数学常项和函数也有一些属性和方法。 比方说, <code>Math对象的</code> <code>PI</code> 属性会有属性值 pi (3.141...),你可以像这样调用它:</p>
+
+<pre class="brush: js notranslate">Math.PI // π
+</pre>
+
+<p>同理,标准数学函数也是Math的方法。 这些包括三角函数​​,对数,指数,和其他函数。比方说你想使用三角函数 <code>sin</code>, 你可以这么写:</p>
+
+<pre class="brush: js notranslate">Math.sin(1.56)
+</pre>
+
+<p>需要注意的是Math的所有三角函数参数都是弧度制。</p>
+
+<p>下面的表格总结了 <code>Math</code> 对象的方法。</p>
+
+<p>Math的方法</p>
+
+<table>
+ <thead>
+ <tr>
+ <th scope="col">方法</th>
+ <th scope="col">描述</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>{{jsxref("Math.abs", "abs()")}}</td>
+ <td>绝对值</td>
+ </tr>
+ <tr>
+ <td>{{jsxref("Math.sin", "sin()")}}, {{jsxref("Math.cos", "cos()")}}, {{jsxref("Math.tan", "tan()")}}</td>
+ <td>标准三角函数;参数为弧度</td>
+ </tr>
+ <tr>
+ <td>{{jsxref("Math.asin", "asin()")}}, {{jsxref("Math.acos", "acos()")}}, {{jsxref("Math.atan", "atan()")}}, {{jsxref("Math.atan2", "atan2()")}}</td>
+ <td>反三角函数; 返回值为弧度</td>
+ </tr>
+ <tr>
+ <td>{{jsxref("Math.sinh", "sinh()")}}, {{jsxref("Math.cosh", "cosh()")}}, {{jsxref("Math.tanh", "tanh()")}}</td>
+ <td>双曲三角函数; 返回值为弧度.</td>
+ </tr>
+ <tr>
+ <td>{{jsxref("Math.asinh", "asinh()")}}, {{jsxref("Math.acosh", "acosh()")}}, {{jsxref("Math.atanh", "atanh()")}}</td>
+ <td>反双曲三角函数;返回值为弧度.</td>
+ </tr>
+ <tr>
+ <td>
+ <p>{{jsxref("Math.pow", "pow()")}}, {{jsxref("Math.exp", "exp()")}}, {{jsxref("Math.expm1", "expm1()")}}, {{jsxref("Math.log10", "log10()")}}, {{jsxref("Math.log1p", "log1p()")}}, {{jsxref("Math.log2", "log2()")}}</p>
+ </td>
+ <td>指数与对数函数</td>
+ </tr>
+ <tr>
+ <td>{{jsxref("Math.floor", "floor()")}}, {{jsxref("Math.ceil", "ceil()")}}</td>
+ <td>返回最大/最小整数小于/大于或等于参数</td>
+ </tr>
+ <tr>
+ <td>{{jsxref("Math.min", "min()")}}, {{jsxref("Math.max", "max()")}}</td>
+ <td>
+ <p>返回一个以逗号间隔的数字参数列表中的较小或较大值(分别地)</p>
+ </td>
+ </tr>
+ <tr>
+ <td>{{jsxref("Math.random", "random()")}}</td>
+ <td>返回0和1之间的随机数。</td>
+ </tr>
+ <tr>
+ <td>{{jsxref("Math.round", "round()")}}, {{jsxref("Math.fround", "fround()")}}, {{jsxref("Math.trunc", "trunc()")}},</td>
+ <td>四舍五入和截断函数</td>
+ </tr>
+ <tr>
+ <td>{{jsxref("Math.sqrt", "sqrt()")}}, {{jsxref("Math.cbrt", "cbrt()")}}, {{jsxref("Math.hypot", "hypot()")}}</td>
+ <td>
+ <p>平方根,立方根,平方参数的和的平方根 </p>
+
+ <p>两个参数平方和的平方根</p>
+ </td>
+ </tr>
+ <tr>
+ <td>{{jsxref("Math.sign", "sign()")}}</td>
+ <td>数字的符号, 说明数字是否为正、负、零。</td>
+ </tr>
+ <tr>
+ <td>{{jsxref("Math.clz32", "clz32()")}},<br>
+ {{jsxref("Math.imul", "imul()")}}</td>
+ <td>
+ <p>在32位2进制表示中,开头的0的数量.</p>
+
+ <p><em>返回传入的两个参数相乘结果的类C的32位表现形式</em></p>
+ </td>
+ </tr>
+ </tbody>
+</table>
+
+<p>和其他对象不同,你不能够创建一个自己的Math对象。你只能使用内置的Math对象。</p>
+
+<h2 id="日期对象"><font face="Consolas, Liberation Mono, Courier, monospace">日期对象</font></h2>
+
+<p>JavaScript没有日期数据类型。但是你可以在你的程序里使用 {{jsxref("Date")}} 对象和其方法来处理日期和时间。Date对象有大量的设置、获取和操作日期的方法。 它并不含有任何属性。</p>
+
+<p>JavaScript 处理日期数据类似于Java。这两种语言有许多一样的处理日期的方法,也都是以1970年1月1日00:00:00以来的毫秒数来储存数据类型的。</p>
+
+<p><code>Date</code> 对象的范围是相对距离 UTC 1970年1月1日 的前后 100,000,000 天。</p>
+
+<p>创建一个日期对象:</p>
+
+<pre class="brush: js notranslate">var dateObjectName = new Date([parameters]);
+</pre>
+
+<p>这里的 dateObjectName 对象是所创建的Date对象的一个名字,它可以成为一个新的对象或者已存在的其他对象的一个属性。</p>
+
+<p>不使用 <em>new </em>关键字来调用Date对象将返回当前时间和日期的字符串</p>
+
+<p>前边的语法中的参数(parameters)可以是一下任何一种:</p>
+
+<ul>
+ <li>无参数 : 创建今天的日期和时间,例如: <code>today = new Date();</code>.</li>
+ <li>一个符合以下格式的表示日期的字符串: "月 日, 年 时:分:秒." 例如: <code>var Xmas95 = new Date("December 25, 1995 13:30:00")。</code>如果你省略时、分、秒,那么他们的值将被设置为0。</li>
+ <li>一个年,月,日的整型值的集合,例如: <code>var Xmas95 = new Date(1995, 11, 25)。</code></li>
+ <li>一个年,月,日,时,分,秒的集合,例如: <code>var Xmas95 = new Date(1995, 11, 25, 9, 30, 0);</code>.</li>
+</ul>
+
+<h3 id="Date对象的方法"><code>Date对象的方法</code></h3>
+
+<p>处理日期时间的Date对象方法可分为以下几类:</p>
+
+<ul>
+ <li>"set" 方法, 用于设置Date对象的日期和时间的值。</li>
+ <li>"get" 方法,用于获取Date对象的日期和时间的值。</li>
+ <li>"to" 方法,用于返回Date对象的字符串格式的值。</li>
+ <li>parse 和UTC 方法, 用于解析Date字符串。</li>
+</ul>
+
+<p>通过“get”和“set”方法,你可以分别设置和获取秒,分,时,日,星期,月份,年。这里有个getDay方法可以返回星期,但是没有相应的setDay方法用来设置星期,因为星期是自动设置的。这些方法用整数来代表以下这些值:</p>
+
+<ul>
+ <li>秒,分: 0 至 59</li>
+ <li>时: 0 至 23</li>
+ <li>星期: 0 (周日) 至 6 (周六)</li>
+ <li>日期:1 至 31 </li>
+ <li>月份: 0 (一月) to 11 (十二月)</li>
+ <li>年份: 从1900开始的年数</li>
+</ul>
+
+<p>例如, 假设你定义了如下日期:</p>
+
+<pre class="brush: js notranslate">var Xmas95 = new Date("December 25, 1995");
+</pre>
+
+<p>Then <code>Xmas95.getMonth()</code> 返回 11, and <code>Xmas95.getFullYear()</code> 返回 1995.</p>
+
+<p><code>getTime</code> 和 <code>setTime</code> 方法对于比较日期是非常有用的。<code>getTime</code>方法返回从1970年1月1日00:00:00的毫秒数。</p>
+
+<p>例如,以下代码展示了今年剩下的天数:</p>
+
+<pre class="brush: js notranslate">var today = new Date();
+var endYear = new Date(1995, 11, 31, 23, 59, 59, 999); // 设置日和月,注意,月份是0-11
+endYear.setFullYear(today.getFullYear()); // 把年设置为今年
+var msPerDay = 24 * 60 * 60 * 1000; // 每天的毫秒数
+var daysLeft = (endYear.getTime() - today.getTime()) / msPerDay;
+var daysLeft = Math.round(daysLeft); //返回今年剩下的天数
+</pre>
+
+<p>这个例子中,创建了一个包含今天的日期的<code>Date</code>对象,并命名为<code>today</code>,然后创建了一个名为<code>endYear</code>的<code>Date</code>对象,并把年份设置为当前年份,接着使用<code>today</code>和<code>endYear</code>的<code>getTime</code>分别获取今天和年底的毫秒数,再根据每一天的毫秒数,计算出了今天到年底的天数,最后四舍五入得到今年剩下的天数。</p>
+
+<p>parse方法对于从日期字符串赋值给现有的Date对象很有用,例如:以下代码使用<code>parse</code>和<code>setTime</code>分配了一个日期值给<code>IPOdate</code>对象:</p>
+
+<pre class="brush: js notranslate">var IPOdate = new Date();
+IPOdate.setTime(Date.parse("Aug 9, 1995"));
+</pre>
+
+<h3 id="例子:">例子:</h3>
+
+<p>在下边的例子中,JSClock()函数返回了用数字时钟格式的时间:</p>
+
+<pre class="brush: js notranslate">function JSClock() {
+ var time = new Date();
+ var hour = time.getHours();
+ var minute = time.getMinutes();
+ var second = time.getSeconds();
+ var temp = "" + ((hour &gt; 12) ? hour - 12 : hour);
+ if (hour == 0)
+ temp = "12";
+ temp += ((minute &lt; 10) ? ":0" : ":") + minute;
+ temp += ((second &lt; 10) ? ":0" : ":") + second;
+ temp += (hour &gt;= 12) ? " P.M." : " A.M.";
+ return temp;
+}
+</pre>
+
+<p><code>JSClock函数首先创建了一个叫做time的新的Date对象,因为没有参数,所以time代表了当前日期和时间。然后调用了</code><code>getHours</code>, <code>getMinutes以及getSeconds方法把当前的时分秒分别赋值给了hour</code>, <code>minute</code>,<code>second。</code></p>
+
+<p>接下来的4句在time的基础上创建了一个字符串,第一句创建了一个变量temp,并通过一个条件表达式进行了赋值,如果小时大于12,就为 (<code>hour - 12</code>), 其他情况就为 hour, 除非 hour 为 0, 这种情况下,它会变成 12.</p>
+
+<p>接下来的语句拼接了<code>minute</code>的值到<code>temp后。如果minute小于10,条件表达式就会在minute前边加个0,其他情况下加一个分号。然后按同样的方式在temp后拼接上了秒。</code></p>
+
+<p>最后,如果hour是12或者更大,条件表达式会在temp后拼接"P.M.",否则拼接"A.M." 。</p>
+
+<p>{{PreviousNext("Web/JavaScript/Guide/Expressions_and_Operators", "Web/JavaScript/Guide/Text_formatting")}}</p>
diff --git a/files/zh-cn/web/javascript/guide/regular_expressions/assertions/index.html b/files/zh-cn/web/javascript/guide/regular_expressions/assertions/index.html
new file mode 100644
index 0000000000..a9ef01776b
--- /dev/null
+++ b/files/zh-cn/web/javascript/guide/regular_expressions/assertions/index.html
@@ -0,0 +1,263 @@
+---
+title: Assertions
+slug: Web/JavaScript/Guide/Regular_Expressions/Assertions
+tags:
+ - JavaScript
+ - 参考
+ - 指南
+ - 正则
+ - 正则表达式
+translation_of: Web/JavaScript/Guide/Regular_Expressions/Assertions
+---
+<p>{{jsSidebar("JavaScript Guide")}}</p>
+
+<p>断言的组成之一是边界。对于文本、词或模式,边界可以用来表明它们的起始或终止部分(如向前断言,向后断言以及条件表达式)。</p>
+
+<p>{{EmbedInteractiveExample("pages/js/regexp-assertions.html", "taller")}}</p>
+
+<h2 id="类型">类型</h2>
+
+<h3 id="边界类断言">边界类断言</h3>
+
+<table>
+ <thead>
+ <tr>
+ <th scope="col">字符</th>
+ <th scope="col">含义</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td><code>^</code></td>
+ <td>
+ <p>匹配输入的开头。如果多行模式设为 true,<code>^</code> 在换行符后也能立即匹配,比如 <code>/^A/</code> 匹配不了 "an A" 里面的 "A",但是可以匹配 "An A" 里面第一个 "A"。</p>
+
+ <div class="blockIndicator note">
+ <p><code>^</code> 出现在集合或范围开头时的含义与此不同(参见 <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions/Groups_and_Ranges">group</a>)。</p>
+ </div>
+ </td>
+ </tr>
+ <tr>
+ <td><code>$</code></td>
+ <td>
+ <p>匹配输入的结束。如果多行模式设为 true,<code>^</code> 在换行符前也能立即匹配,比如 <code>/t$/</code> 不能匹配  "eater" 中的 "t",但是可以匹配 "eat" 中的 "t"。</p>
+ </td>
+ </tr>
+ <tr>
+ <td><code>\b</code></td>
+ <td>
+ <p>匹配一个单词的边界,这是一个字的字符前后没有另一个字的字符位置, 例如在字母和空格之间。需要注意的是匹配的单词边界不包括在匹配中。换句话说,匹配字边界的长度为零。</p>
+
+ <p>一些例子:</p>
+
+ <ul>
+ <li><code>/\bm/</code>  在 "moon" 中匹配到 "m" </li>
+ <li><code>/oo\b/</code>  在 "moon" 中不会匹配到 "oo", 因为 "oo" 后面跟着 "n" 这个单词字符.</li>
+ <li><code>/oon\b/</code> 在 "moon" 中匹配 "oon", 因为 "oon" 是这个字符串的结尾, 因此后面没有单词字符</li>
+ <li><code>/\w\b\w/</code> 将永远不会匹配任何东西,因为一个单词字符后面永远不会有非单词字符和单词字符。</li>
+ </ul>
+
+ <p>匹配退格字符 (<code>[\b]</code>), 查看 <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions/Character_Classes">字符类</a> </p>
+ </td>
+ </tr>
+ <tr>
+ <td><code>\B</code></td>
+ <td>
+ <p>匹配非单词边界。这是上一个字符和下一个字符属于同一类型的位置:要么两者都必须是单词,要么两者都必须是非单词,例如在两个字母之间或两个空格之间。字符串的开头和结尾被视为非单词。与匹配的词边界相同,匹配的非词边界也不包含在匹配中。例如,<code>/\Bon/</code> 在 “at noon” 中匹配 “on” ,<code>/ye\B/</code> 在 "possibly yesterday"中匹配"ye" 。</p>
+ </td>
+ </tr>
+ </tbody>
+</table>
+
+<h3 id="其他断言">其他断言 </h3>
+
+<div class="blockIndicator note">
+<p>提示:<code>?</code>字符也可用作量词</p>
+</div>
+
+<table class="standard-table">
+ <thead>
+ <tr>
+ <th scope="col"><code>字符</code></th>
+ <th scope="col"><code>含义</code></th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>
+ <p><code>x(?=y)</code>                </p>
+ </td>
+ <td>
+ <table>
+ <tbody>
+ <tr>
+ <td><strong>向前断言:</strong> x 被 y 跟随时匹配 x。例如,对于/<code>Jack(?=Sprat)</code>/,“Jack”在跟有“Sprat”的情况下才会得到匹配.<code>/Jack(?=Sprat|Frost)/</code> “Jack”后跟有“Sprat”或“Frost”的情况下才会得到匹配。不过, 匹配结果不包括“Sprat”或“Frost”。</td>
+ </tr>
+ </tbody>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td>x(?!y)</td>
+ <td>
+ <table>
+ <tbody>
+ <tr>
+ <td><strong>向前否定断言:</strong> x 没有被 y 紧随时匹配 x。例如,对于<code>/\d+(?!\。)/</code>,数字后没有跟随小数点的情况下才会得到匹配。对于<code>/\d+(?!\.)/.exec(3.141)</code>,匹配‘141’而不是‘3’。</td>
+ </tr>
+ </tbody>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td>(?&lt;=y)x</td>
+ <td>
+ <table>
+ <tbody>
+ <tr>
+ <td><strong>向后断言:</strong> x 跟随 y 的情况下匹配 x。例如,对于<code>/(?&lt;=Jack)Sprat/</code>,“Sprat”紧随“Jack”时才会得到匹配。对于<code>/(?&lt;=Jack|Tom)Sprat</code>,“Sprat”在紧随“Jack”或“Tom”的情况下才会得到匹配。不过,匹配结果中不包括“Jack”或“Tom”。</td>
+ </tr>
+ </tbody>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td>(?&lt;!y)x</td>
+ <td>
+ <table>
+ <tbody>
+ <tr>
+ <td><strong>向后否定断言:</strong> x 不跟随 y 时匹配 x。例如,对于<code>/(?&lt;!-)\d+/</code>,数字不紧随-符号的情况下才会得到匹配。对于<code>/(?&lt;!-)\d+/.exec(3)</code> ,“3”得到匹配。 而<code>/(?&lt;!-)\d+/.exec(-3)</code>的结果无匹配,这是由于数字之前有-符号。</td>
+ </tr>
+ </tbody>
+ </table>
+ </td>
+ </tr>
+ </tbody>
+</table>
+
+<h2 id="示例">示例</h2>
+
+<h3 id="一般边界类型概述示例">一般边界类型概述示例</h3>
+
+<pre class="notranslate">// 使用 正则表达式边界修复错误字符串
+buggyMultiline = `tey, ihe light-greon apple
+tangs on ihe greon traa`;
+
+// 1) 使用 ^ 修正字符串开始处和换行后的匹配.
+buggyMultiline = buggyMultiline.replace(/^t/gim,'h');
+console.log(1, buggyMultiline); // 修复 'tey'=&gt;'hey'(字符串开始) , 'tangs'=&gt;'hangs'(换行后)
+
+// 2) 使用 $ 修正字符串结尾处的匹配.
+buggyMultiline = buggyMultiline.replace(/aa$/gim,'ee.');
+console.log(2, buggyMultiline); // 修复 'traa' =&gt; 'tree'.
+
+// 3) 使用 \b 修正单词和空格边界上的字符.
+buggyMultiline = buggyMultiline.replace(/\bi/gim,'t');
+console.log(3, buggyMultiline); // 修复 'ihe' =&gt; 'the' 不影响 'light'.
+
+// 4) 使用 \B 匹配实体边界内的字符.
+fixedMultiline = buggyMultiline.replace(/\Bo/gim,'e');
+console.log(4, fixedMultiline); // 修复 'greon' 不影响'on'.</pre>
+
+<h3 id="使用_(控制字符)匹配输入的开头">使用 ^(控制字符)匹配输入的开头</h3>
+
+<p>使用 <code>^</code>匹配输入的开头。在这个例子中,我们可以通过 /^A/ 正则表达式得到以A开头的水果。为了选择合适的水果,我们可以使用带有箭头函数的过滤方法.</p>
+
+<pre class="notranslate">let fruits = ["Apple", "Watermelon", "Orange", "Avocado", "Strawberry"];
+
+// 使用正则 /^A/ 选择以'A'开头的水果.
+// 这里的 '^' 只有一种含义: 匹配输入的开头.
+
+let fruitsStartsWithA = fruits.filter(fruit =&gt; /^A/.test(fruit));
+console.log(fruitsStartsWithA); // [ 'Apple', 'Avocado' ]</pre>
+
+<p>在第二个示例中,^用于在输入的开始处匹配,以及在内部使用时用于创建否定或被补充的字符集 <a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Guide/Regular_Expressions/Groups_and_Ranges">组和范围</a>.</p>
+
+<pre class="notranslate">let fruits = ["Apple", "Watermelon", "Orange", "Avocado", "Strawberry"];
+
+// 使用正则 /^[^A]/ 选择 不是以 ‘A’ 开头的水果
+// 在这个例子中,“^” 控件符号表示两种含义:
+// 1) 匹配输入的开头
+// 2) 一个否定的字符集: [^A] ,意思是匹配不是 ‘A’ 的字符
+
+let fruitsStartsWithNotA = fruits.filter(fruit =&gt; /^[^A]/.test(fruit));
+
+console.log(fruitsStartsWithNotA); // [ 'Watermelon', 'Orange', 'Strawberry' ]</pre>
+
+<h3 id="匹配字边界">匹配字边界</h3>
+
+<pre class="notranslate">let fruitsWithDescription = ["Red apple", "Orange orange", "Green Avocado"];
+
+// 选择包含以 “en” 或 “ed” 结尾的单词的描述:
+let enEdSelection = fruitsWithDescription.filter(descr =&gt; /(en|ed)\b/.test(descr));
+
+console.log(enEdSelection); // [ 'Red apple', 'Green Avocado' ]</pre>
+
+<h3 id="向前断言">向前断言</h3>
+
+<pre class="notranslate">// JS 向前断言 x(?=y) 匹配被 y 跟随的 x
+
+let regex = /First(?= test)/g;
+
+console.log('First test'.match(regex)); // [ 'First' ]
+console.log('test First peach'.match(regex)); // null
+console.log('This is a First test in a year.'.match(regex)); // [ 'First' ]
+console.log('This is a First peach in a month.'.match(regex)); // null</pre>
+
+<h3 id="向前否定断言">向前否定断言</h3>
+
+<p>例如, <code>/\d+(?!\.)/</code> 匹配没有被小数点跟随且至少有一位的数字。 <code>/\d+(?!\.)/.exec('3.141')</code> 匹配 "141" 而不是 "3" </p>
+
+<pre class="notranslate">console.log(/\d+(?!\.)/g.exec('3.141')); // [ '141', index: 2, input: '3.141' ]</pre>
+
+<h3 id="不同含义的!:断言和范围的组合用法">不同含义的'?!':断言和范围的组合用法</h3>
+
+<p>不同含义的<code>?!</code> 结合使用 <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions/Assertions">断言</a>  <code>/x(?!y)/ </code>和  <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions/Groups_and_Ranges">范围</a> <code>[^?!]</code>.</p>
+
+<pre class="notranslate">let orangeNotLemon = "Do you want to have an orange? Yes, I do not want to have a lemon!";
+
+let selectNotLemonRegex = /[^?!]+have(?! a lemon)[^?!]+[?!]/gi
+console.log(orangeNotLemon.match(selectNotLemonRegex)); // [ 'Do you want to have an orange?' ]
+
+let selectNotOrangeRegex = /[^?!]+have(?! an orange)[^?!]+[?!]/gi
+console.log(orangeNotLemon.match(selectNotOrangeRegex)); // [ ' Yes, I do not want to have a lemon!' ]</pre>
+
+<h3 id="向后断言">向后断言</h3>
+
+<pre class="notranslate">let oranges = ['ripe orange A ', 'green orange B', 'ripe orange C',];
+
+let ripe_oranges = oranges.filter( fruit =&gt; fruit.match(/(?&lt;=ripe )orange/));
+console.log(ripe_oranges); // [ 'ripe orange A ', 'ripe orange C' ]</pre>
+
+<h2 id="规范">规范</h2>
+
+<table>
+ <tbody>
+ <tr>
+ <th scope="col">详述</th>
+ </tr>
+ <tr>
+ <td>{{SpecName('ESDraft', '#sec-assertion', 'RegExp: Assertions')}}</td>
+ </tr>
+ </tbody>
+</table>
+
+<h2 id="浏览器_兼容性">浏览器 兼容性</h2>
+
+<p>有关浏览器兼容性的信息,请查看 <a href="https://wiki.developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#Browser_compatibility">main Regular Expressions compatibility table</a>.</p>
+
+<h2 id="另请参阅">另请参阅</h2>
+
+<ul>
+ <li><a href="https://wiki.developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions">正则表达式指南</a>
+
+ <ul>
+ <li><a href="https://wiki.developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions/Character_Classes">字符类</a></li>
+ <li><a href="https://wiki.developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions/Quantifiers">量词</a> </li>
+ <li><a href="https://wiki.developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions/Unicode_Property_Escapes">Unicode 属性转义</a></li>
+ <li><a href="https://wiki.developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions/Groups_and_Ranges">组和范围</a></li>
+ </ul>
+ </li>
+ <li> <a href="https://wiki.developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp">RegExp() 构造器</a></li>
+</ul>
diff --git a/files/zh-cn/web/javascript/guide/regular_expressions/boundaries/index.html b/files/zh-cn/web/javascript/guide/regular_expressions/boundaries/index.html
new file mode 100644
index 0000000000..0c5b2f4eb9
--- /dev/null
+++ b/files/zh-cn/web/javascript/guide/regular_expressions/boundaries/index.html
@@ -0,0 +1,6 @@
+---
+title: Boundaries
+slug: Web/JavaScript/Guide/Regular_Expressions/Boundaries
+translation_of: Web/JavaScript/Guide/Regular_Expressions/Assertions
+---
+<p>重定向至 <a class="redirect" href="/zh-CN/docs/Web/JavaScript/Guide/Regular_Expressions/Assertions">断言</a></p>
diff --git a/files/zh-cn/web/javascript/guide/regular_expressions/character_classes/index.html b/files/zh-cn/web/javascript/guide/regular_expressions/character_classes/index.html
new file mode 100644
index 0000000000..26b1f4ee4a
--- /dev/null
+++ b/files/zh-cn/web/javascript/guide/regular_expressions/character_classes/index.html
@@ -0,0 +1,216 @@
+---
+title: 字符类
+slug: Web/JavaScript/Guide/Regular_Expressions/Character_Classes
+tags:
+ - 字符类
+translation_of: Web/JavaScript/Guide/Regular_Expressions/Character_Classes
+---
+<p>{{JSSidebar("JavaScript Guide")}}</p>
+
+<p>字符类可以区分各种字符,例如区分字母和数字。</p>
+
+<div>{{EmbedInteractiveExample("pages/js/regexp-character-classes.html")}}</div>
+
+<h2 id="类型">类型</h2>
+
+<div class="hidden">The following table is also duplicated on <a href="/en-US/docs/Web/JavaScript/Guide/Regular_Expressions/Cheatsheet">this cheatsheet</a>. Do not forget to edit it as well, thanks!</div>
+
+<table class="standard-table">
+ <thead>
+ <tr>
+ <th scope="col">Characters</th>
+ <th scope="col">Meaning</th>
+ </tr>
+ </thead>
+ <tbody>
+ </tbody>
+ <tbody>
+ <tr>
+ <td><code>.</code></td>
+ <td>
+ <p>有下列含义之一:</p>
+
+ <ul>
+ <li>匹配除行终止符之外的任何单个字符: <code>\n</code>, <code>\r</code>, <code>\u2028</code> or <code>\u2029</code>. 例如, <code>/.y/</code> 在“yes make my day”中匹配“my”和“ay”,而不是“yes”。</li>
+ <li>在字符集内,点失去了它的特殊意义,并与文字点匹配。</li>
+ </ul>
+
+ <p>需要注意的是,<code>m</code> multiline标志不会改变点的行为。因此,要跨多行匹配一个模式,可以使用字符集<code>[^]</code>—它将匹配任何字符,包括新行。</p>
+
+ <p>ES2018 添加了 <code>s</code> "dotAll" 标志,它允许点也匹配行终止符。</p>
+ </td>
+ </tr>
+ <tr>
+ <td><code>\d</code></td>
+ <td>
+ <p>匹配任何数字(阿拉伯数字)。 相当于 <code>[0-9]</code>. 例如, <code>/\d/</code> 或 <code>/[0-9]/</code> 匹配 “B2is the suite number”中的“2”。</p>
+ </td>
+ </tr>
+ <tr>
+ <td><code>\D</code></td>
+ <td>
+ <p>匹配任何非数字(阿拉伯数字)的字符。相当于<code>[^0-9]</code>. 例如, <code>/\D/</code> or <code>/[^0-9]/</code> 在 "B2 is the suite number" 中 匹配 "B".</p>
+ </td>
+ </tr>
+ <tr>
+ <td><code>\w</code></td>
+ <td>
+ <p>匹配基本拉丁字母中的任何字母数字字符,包括下划线。相当于 <code>[A-Za-z0-9_]</code>. 例如, <code>/\w/</code> 在 "apple" 匹配 "a" , "5" in "$5.28", "3" in "3D" and "m" in "Émanuel".</p>
+ </td>
+ </tr>
+ <tr>
+ <td><code>\W</code></td>
+ <td>
+ <p>匹配任何不是来自基本拉丁字母的单词字符。相当于 <code>[^A-Za-z0-9_]</code>. 例如, <code>/\W/</code> or <code>/[^A-Za-z0-9_]/</code> 匹配 "%" 在 "50%" 以及 "É" 在 "Émanuel" 中.</p>
+ </td>
+ </tr>
+ <tr>
+ <td><code>\s</code></td>
+ <td>
+ <p>Matches a single white space character, including space, tab, form feed, line feed, and other Unicode spaces. Equivalent to <code>[ \f\n\r\t\v\u00a0\u1680\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff]</code>. For example, <code>/\s\w*/</code> matches " bar" in "foo bar".</p>
+ </td>
+ </tr>
+ <tr>
+ <td><code>\S</code></td>
+ <td>
+ <p>Matches a single character other than white space. Equivalent to <code>[^ \f\n\r\t\v\u00a0\u1680\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff]</code>. For example, <code>/\S\w*/</code> matches "foo" in "foo bar".</p>
+ </td>
+ </tr>
+ <tr>
+ <td><code>\t</code></td>
+ <td>Matches a horizontal tab.</td>
+ </tr>
+ <tr>
+ <td><code>\r</code></td>
+ <td>Matches a carriage return.</td>
+ </tr>
+ <tr>
+ <td><code>\n</code></td>
+ <td>Matches a linefeed.</td>
+ </tr>
+ <tr>
+ <td><code>\v</code></td>
+ <td>Matches a vertical tab.</td>
+ </tr>
+ <tr>
+ <td><code>\f</code></td>
+ <td>Matches a form-feed.</td>
+ </tr>
+ <tr>
+ <td><code>[\b]</code></td>
+ <td>Matches a backspace. If you're looking for the word-boundary character (<code>\b</code>), see <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions/Boundaries">Boundaries</a>.</td>
+ </tr>
+ <tr>
+ <td><code>\0</code></td>
+ <td>Matches a NUL character. Do not follow this with another digit.</td>
+ </tr>
+ <tr>
+ <td><code>\c<em>X</em></code></td>
+ <td>
+ <p>Matches a control character using <a href="https://en.wikipedia.org/wiki/Caret_notation">caret notation</a>, where "X" is a letter from A–Z (corresponding to codepoints <code>U+0001</code><em>–</em><code>U+001F</code>). For example, <code>/\cM/</code> matches "\r" in "\r\n".</p>
+ </td>
+ </tr>
+ <tr>
+ <td><code>\x<em>hh</em></code></td>
+ <td>Matches the character with the code <code><em>hh</em></code> (two hexadecimal digits).</td>
+ </tr>
+ <tr>
+ <td><code>\u<em>hhhh</em></code></td>
+ <td>Matches a UTF-16 code-unit with the value <code><em>hhhh</em></code> (four hexadecimal digits).</td>
+ </tr>
+ <tr>
+ <td><code>\u<em>{hhhh} </em>or <em>\u{hhhhh}</em></code></td>
+ <td>(Only when the <code>u</code> flag is set.) Matches the character with the Unicode value <code>U+<em>hhhh</em></code> or <code>U+<em>hhhhh</em></code> (hexadecimal digits).</td>
+ </tr>
+ <tr>
+ <td><code>\</code></td>
+ <td>
+ <p>Indicates that the following character should be treated specially, or "escaped". It behaves one of two ways.</p>
+
+ <ul>
+ <li>For characters that are usually treated literally, indicates that the next character is special and not to be interpreted literally. For example, <code>/b/</code> matches the character "b". By placing a backslash in front of "b", that is by using <code>/\b/</code>, the character becomes special to mean match a word boundary.</li>
+ <li>For characters that are usually treated specially, indicates that the next character is not special and should be interpreted literally. For example, "*" is a special character that means 0 or more occurrences of the preceding character should be matched; for example, <code>/a*/</code> means match 0 or more "a"s. To match <code>*</code> literally, precede it with a backslash; for example, <code>/a\*/</code> matches "a*".</li>
+ </ul>
+
+ <div class="blockIndicator note">
+ <p>To match this character literally, escape it with itself. In other words to search for <code>\</code> use <code>/\\/</code>.</p>
+ </div>
+ </td>
+ </tr>
+ </tbody>
+</table>
+
+<h2 id="Examples">Examples</h2>
+
+<h3 id="Looking_for_a_series_of_digits">Looking for a series of digits</h3>
+
+<pre class="brush: js notranslate">var randomData = "015 354 8787 687351 3512 8735";
+var regexpFourDigits = /\b\d{4}\b/g;
+// \b indicates a boundary (i.e. do not start matching in the middle of a word)
+// \d{4} indicates a digit, four times
+// \b indicates another boundary (i.e. do not end matching in the middle of a word)
+
+
+console.table(randomData.match(regexpFourDigits));
+// ['8787', '3512', '8735']
+</pre>
+
+<h3 id="Looking_for_a_word_from_the_latin_alphabet_starting_with_A">Looking for a word (from the latin alphabet) starting with A</h3>
+
+<pre class="brush: js notranslate">var aliceExcerpt = "I’m sure I’m not Ada,’ she said, ‘for her hair goes in such long ringlets, and mine doesn’t go in ringlets at all.";
+var regexpWordStartingWithA = /\b[aA]\w+/g;
+// \b indicates a boundary (i.e. do not start matching in the middle of a word)
+// [aA] indicates the letter a or A
+// \w+ indicates any character *from the latin alphabet*, multiple times
+
+console.table(aliceExcerpt.match(regexpWordStartingWithA));
+// ['Ada', 'and', 'at', 'all']
+</pre>
+
+<h3 id="Looking_for_a_word_from_Unicode_characters">Looking for a word (from Unicode characters)</h3>
+
+<p>Instead of the Latin alphabet, we can use a range of Unicode characters to identify a word (thus being able to deal with text in other languages like Russian or Arabic). The "Basic Multilingual Plane" of Unicode contains most of the characters used around the world and we can use character classes and ranges to match words written with those characters.</p>
+
+<pre class="brush: js notranslate">var nonEnglishText = "Приключения Алисы в Стране чудес";
+var regexpBMPWord = /([\u0000-\u0019\u0021-\uFFFF])+/gu;
+// BMP goes through U+0000 to U+FFFF but space is U+0020
+
+console.table(nonEnglishText.match(regexpBMPWord));
+[ 'Приключения', 'Алисы', 'в', 'Стране', 'чудес' ]
+</pre>
+
+<div class="hidden">
+<p>Note for MDN editors: please do not try to add funny examples with emoji as those characters are not handled by the platform (Kuma).</p>
+</div>
+
+<h2 id="Specifications">Specifications</h2>
+
+<table class="standard-table">
+ <tbody>
+ <tr>
+ <th scope="col">Specification</th>
+ </tr>
+ <tr>
+ <td>{{SpecName('ESDraft', '#sec-characterclass', 'RegExp: Character classes')}}</td>
+ </tr>
+ </tbody>
+</table>
+
+<h2 id="Browser_compatibility">Browser compatibility</h2>
+
+<p>For browser compatibility information, check out the <a href="/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#Browser_compatibility">main Regular Expressions compatibility table</a>.</p>
+
+<h2 id="See_also">See also</h2>
+
+<ul>
+ <li><a href="/en-US/docs/Web/JavaScript/Guide/Regular_Expressions">Regular expressions guide</a>
+
+ <ul>
+ <li><a href="/en-US/docs/Web/JavaScript/Guide/Regular_Expressions/Assertions">Assertions</a></li>
+ <li><a href="/en-US/docs/Web/JavaScript/Guide/Regular_Expressions/Quantifiers">Quantifiers</a></li>
+ <li><a href="/en-US/docs/Web/JavaScript/Guide/Regular_Expressions/Unicode_Property_Escapes">Unicode property escapes</a></li>
+ <li><a href="/en-US/docs/Web/JavaScript/Guide/Regular_Expressions/Groups_and_Ranges">Groups and ranges</a></li>
+ </ul>
+ </li>
+ <li><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp">The <code>RegExp()</code> constructor</a></li>
+</ul>
diff --git a/files/zh-cn/web/javascript/guide/regular_expressions/groups_and_ranges/index.html b/files/zh-cn/web/javascript/guide/regular_expressions/groups_and_ranges/index.html
new file mode 100644
index 0000000000..9a73c9b8ef
--- /dev/null
+++ b/files/zh-cn/web/javascript/guide/regular_expressions/groups_and_ranges/index.html
@@ -0,0 +1,164 @@
+---
+title: Groups and ranges
+slug: Web/JavaScript/Guide/Regular_Expressions/Groups_and_Ranges
+translation_of: Web/JavaScript/Guide/Regular_Expressions/Groups_and_Ranges
+---
+<p>{{jsSidebar("JavaScript Guide")}}</p>
+
+<p>组和范围表示表达式字符的 组和范围</p>
+
+<div>{{EmbedInteractiveExample("pages/js/regexp-groups-ranges.html")}}</div>
+
+<h2 id="类型">类型</h2>
+
+<div class="hidden">The following section is also duplicated on <a href="/en-US/docs/Web/JavaScript/Guide/Regular_Expressions/Cheatsheet">this cheatsheet</a>. Do not forget to edit it as well, thanks!</div>
+
+<table class="standard-table">
+ <thead>
+ <tr>
+ <th scope="col">字符集</th>
+ <th scope="col">含义</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td><code><em>x</em>|<em>y</em></code></td>
+ <td>
+ <p>匹配 "x" 或 "y" 任意一个字符。例如, <code>/green|red/</code> 在 "green apple" 里匹配 "green",且在 "red apple" 里匹配 "red" 。</p>
+ </td>
+ </tr>
+ <tr>
+ <td><code>[xyz]<br>
+ [a-c]</code></td>
+ <td>
+ <p>字符集。 匹配任何一个包含的字符。您可以使用连字符来指定字符范围,但如果连字符显示为方括号中的第一个或最后一个字符,则它将被视为作为普通字符包含在字符集中的文字连字符。也可以在字符集中包含字符类。</p>
+
+ <p>例如, <code>[abcd]</code> 是与<code>[a-d]</code>.一样的,它们会 在"brisket" 中匹配 "b",在 "chop" 中匹配 "c" .</p>
+
+ <p>例如, <code>[abcd-]</code> 和<code>[-abcd]</code> 将会在 "brisket" 匹配 "b" , 在 "chop" 匹配 "c" , 并且匹配 "non-profit" 中的 "-" (连字符)</p>
+
+ <p>例如, <code>[\w-]</code> 是字符集 \w 和 “-”(连字符)的并集,与这种写法一样: <code>[A-Za-z0-9_-]</code>.。他们都会 在 "brisket"中匹配 “b”,  在 "chop"中匹配 “c”, 在 "non-profit" 中匹配 "n"。</p>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <p><code>[^xyz]<br>
+ [^a-c]</code></p>
+ </td>
+ <td>
+ <p>一个否定的或被补充的字符集。也就是说,它匹配任何没有包含在括号中的字符。可以通过使用连字符来指定字符范围,但是如果连字符作为方括号中的第一个或最后一个字符出现,那么它将被视为作为普通字符包含在字符集中。例如,[^abc]和[^a-c]一样。它们最初匹配“bacon”中的“o”和“chop”中的“h”。</p>
+
+ <div class="blockIndicator note">
+ <p> ^ 字符也可以表示   <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions/Boundaries">输入的起始</a></p>
+ </div>
+ </td>
+ </tr>
+ <tr>
+ <td><code>(<em>x</em>)</code></td>
+ <td>
+ <p><strong>捕获组: </strong>匹配x并记住匹配项。例如,/(foo)/匹配并记住“foo bar”中的“foo” </p>
+
+ <p>正则表达式可以有多个捕获组。结果,匹配通常在数组中捕获的组,该数组的成员与捕获组中左括号的顺序相同。这通常只是捕获组本身的顺序。当捕获组被嵌套时,这一点非常重要。使用结果元素的索引 (<code>[1], ..., [n]</code>) 或从预定义的 <code>RegExp</code> 对象的属性 (<code>$1, ..., $9</code>).</p>
+
+ <p>捕获组会带来性能损失。如果不需要收回匹配的子字符串,请选择非捕获括号(见下面)。</p>
+
+ <p><code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/match">String.match()</a></code> 不会返回组,如果设置了 <code>/.../g</code> 标志. 但是,您仍然可以使用 <code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/matchAll">String.matchAll()</a></code> to get all matches.</p>
+
+ <p>match()不会返回组,如果/…但是,您仍然可以使用String.matchAll()来获取所有匹配项。</p>
+ </td>
+ </tr>
+ <tr>
+ <td><code>\<em>n</em></code></td>
+ <td>
+ <p>其中n是一个正整数。对正则表达式中与n括号匹配的最后一个子字符串的反向引用(计算左括号)。例如,<code>/apple(,)\sorange\1/</code> 匹配 “apple,orange,cherry,peach” 中的 "apple,orange,", 其中 <code>\1</code> 引用了 之前使用 <code>()</code> 捕获的 <code>,</code></p>
+ </td>
+ </tr>
+ <tr>
+ <td><code>(?&lt;Name&gt;x)</code></td>
+ <td>
+ <p><strong>具名捕获组: </strong>匹配"x"并将其存储在返回的匹配项的groups属性中,该属性位于<code>&lt;Name&gt;</code>指定的名称下。尖括号(<code>&lt;</code> 和 <code>&gt;</code>) 用于组名。</p>
+
+ <p>例如,使用正则 <code>/-(?&lt;customName&gt;\w)/</code> 匹配 “web-doc” 中的 “d”</p>
+
+ <p><code>'web-doc'.match(/-(?&lt;customName&gt;\w)/).groups   //{customName: "d"} </code>   </p>
+ </td>
+ </tr>
+ <tr>
+ <td><code>(?:<em>x</em>)</code></td>
+ <td><strong>非捕获组: </strong>匹配 “x”,但不记得匹配。不能从结果数组的元素中收回匹配的子字符串(<code>[1], ..., [n]</code>) or from the predefined <code>RegExp</code> object's properties (<code>$1, ..., $9</code>).</td>
+ </tr>
+ </tbody>
+</table>
+
+<h2 id="一些例子">一些例子</h2>
+
+<h3 id="计算元音数">计算元音数</h3>
+
+<pre class="brush: js notranslate">var aliceExcerpt = "There was a long silence after this, and Alice could only hear whispers now and then.";
+var regexpVowels = /[aeiouy]/g;
+
+console.log("Number of vowels:", aliceExcerpt.match(regexpVowels).length);
+// Number of vowels: 25</pre>
+
+<h3 id="使用_组">使用 组</h3>
+
+<pre class="brush: js notranslate">let personList = `First_Name: John, Last_Name: Doe
+First_Name: Jane, Last_Name: Smith`;
+
+let regexpNames =  /First_Name: (\w+), Last_Name: (\w+)/mg;
+let match = regexpNames.exec(personList);
+do {
+  console.log(`Hello ${match[1]} ${match[2]}`);
+} while((match = regexpNames.exec(personList)) !== null);
+</pre>
+
+<h3 id="使用命名组">使用命名组</h3>
+
+<pre class="brush: js notranslate">let users= `姓氏: 李, 名字: 雷
+姓氏: 韩, 名字: 梅梅`;
+
+let regexpNames = /姓氏: (?&lt;first&gt;.+), 名字: (?&lt;last&gt;.+)/mg;
+let match = regexpNames.exec(users);
+
+do {
+  console.log(`Hello ${match.groups.first} ${match.groups.last}`);
+} while((match = regexpNames.exec(users)) !== null);
+
+// Hellow 李 雷
+// Hellow 韩 梅梅</pre>
+
+<div class="blockIndicator note">
+<p><strong>Note:</strong> 并不是所有的浏览器都支持这个功能; 参考兼容表: <a href="/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#Browser_compatibility">compatibility table</a>.</p>
+</div>
+
+<h2 id="技术指标">技术指标</h2>
+
+<table class="standard-table">
+ <tbody>
+ <tr>
+ <th scope="col">技术指标</th>
+ </tr>
+ <tr>
+ <td>{{SpecName('ESDraft', '#sec-classranges', 'RegExp: Ranges')}}</td>
+ </tr>
+ </tbody>
+</table>
+
+<h2 id="浏览器兼容性">浏览器兼容性</h2>
+
+<p>有关浏览器兼容性的信息,请查看 <a href="/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#Browser_compatibility">main Regular Expressions compatibility table</a>.</p>
+
+<h2 id="另请参阅">另请参阅</h2>
+
+<ul>
+ <li><a href="/en-US/docs/Web/JavaScript/Guide/Regular_Expressions">正则表达式指南</a>
+
+ <ul>
+ <li><a href="/en-US/docs/Web/JavaScript/Guide/Regular_Expressions/Character_Classes">字符类</a></li>
+ <li><a href="/en-US/docs/Web/JavaScript/Guide/Regular_Expressions/Assertions">断言</a></li>
+ <li><a href="/en-US/docs/Web/JavaScript/Guide/Regular_Expressions/Quantifiers">量词</a></li>
+ <li><a href="/en-US/docs/Web/JavaScript/Guide/Regular_Expressions/Unicode_Property_Escapes">Unicode 属性转义</a></li>
+ </ul>
+ </li>
+ <li><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp">正则构造函数</a></li>
+</ul>
diff --git a/files/zh-cn/web/javascript/guide/regular_expressions/index.html b/files/zh-cn/web/javascript/guide/regular_expressions/index.html
new file mode 100644
index 0000000000..4d88167c80
--- /dev/null
+++ b/files/zh-cn/web/javascript/guide/regular_expressions/index.html
@@ -0,0 +1,745 @@
+---
+title: 正则表达式
+slug: Web/JavaScript/Guide/Regular_Expressions
+tags:
+ - JavaScript
+ - RegExp
+ - Regular Expressions
+ - 中级
+ - 参考
+ - 指南
+ - 正则表达式
+translation_of: Web/JavaScript/Guide/Regular_Expressions
+---
+<p>{{jsSidebar("JavaScript Guide")}} {{PreviousNext("Web/JavaScript/Guide/Text_formatting", "Web/JavaScript/Guide/Indexed_collections")}}</p>
+
+<p>正则表达式是用于匹配字符串中字符组合的模式。在 JavaScript中,正则表达式也是对象。这些模式被用于 {{jsxref("RegExp")}} 的 {{jsxref("RegExp.exec", "exec")}} 和 {{jsxref("RegExp.test", "test")}} 方法, 以及 {{jsxref("String")}} 的 {{jsxref("String.match", "match")}}、{{jsxref("String.matchAll", "matchAll")}}、{{jsxref("String.replace", "replace")}}、{{jsxref("String.search", "search")}} 和 {{jsxref("String.split", "split")}} 方法。本章介绍 JavaScript 正则表达式。</p>
+
+<h2 id="创建一个正则表达式">创建一个正则表达式</h2>
+
+<p>你可以使用以下两种方法构建一个正则表达式:</p>
+
+<p>使用一个正则表达式字面量,其由包含在斜杠之间的模式组成,如下所示:</p>
+
+<pre class="brush: js notranslate">var re = /ab+c/;
+</pre>
+
+<p>脚本加载后,正则表达式字面量就会被编译。当正则表达式保持不变时,使用此方法可获得更好的性能。</p>
+
+<p>或者调用<code><a href="/zh-CN/docs/JavaScript/Reference/Global_Objects/RegExp" title="zh-CN/docs/JavaScript/Reference/Global Objects/RegExp">RegExp</a></code>对象的构造函数,如下所示:</p>
+
+<pre class="brush: js notranslate">var re = new RegExp("ab+c");
+</pre>
+
+<p>在脚本运行过程中,用构造函数创建的正则表达式会被编译。如果正则表达式将会改变,或者它将会从用户输入等来源中动态地产生,就需要使用构造函数来创建正则表达式。</p>
+
+<h2 id="编写一个正则表达式的模式">编写一个正则表达式的模式</h2>
+
+<p>一个正则表达式模式是由简单的字符所构成的,比如 <code>/abc/</code>;或者是简单和特殊字符的组合,比如 <code>/ab*c/</code> 或 <code>/Chapter (\d+)\.\d*/</code>。最后的例子中用到了括号,它在正则表达式中常用作记忆设备。即这部分所匹配的字符将会被记住以备后续使用,例如<a href="#使用括号的子字符串匹配">使用括号的子字符串匹配</a>。</p>
+
+<h3 id="使用简单模式">使用简单模式</h3>
+
+<p>简单模式是由你想直接找到的字符构成。比如,<code>/abc/</code> 这个模式就能且仅能匹配 "abc" 字符按照顺序同时出现的情况。例如在 "Hi, do you know your abc's?" 和 "The latest airplane designs evolved from slabcraft." 中会匹配成功。在上述两个例子中,匹配的子字符串是 "abc"。但是在 "Grab crab" 中会匹配失败,因为它虽然包含子字符串 "ab c",但并不是准确的 "abc"。</p>
+
+<h3 id="使用特殊字符">使用特殊字符</h3>
+
+<p>当你需要匹配一个不确定的字符串时,比如寻找一个或多个 "b",或者寻找空格,可以在模式中使用特殊字符。比如,你可以使用 <code>/ab*c/</code> 去匹配一个单独的 "a" 后面跟了零个或者多个 "b",同时后面跟着 "c" 的字符串:<code>*</code>的意思是前一项出现零次或者多次。在字符串 "cbbabbbbcdebc" 中,这个模式匹配了子字符串 "abbbbc"。</p>
+
+<p>下面的页面与表格列出了一个正则表达式中可以利用的特殊字符的完整列表和描述。</p>
+
+<dl>
+ <dt><a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Guide/Regular_Expressions/Assertions">断言(Assertions)</a></dt>
+ <dd>表示一个匹配在某些条件下发生。断言包含先行断言、后行断言和条件表达式。</dd>
+ <dt><a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Guide/Regular_Expressions/Character_Classes">字符类(Character Classes)</a></dt>
+ <dd>区分不同类型的字符,例如区分字母和数字。</dd>
+ <dt><a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Guide/Regular_Expressions/Groups_and_Ranges">组和范围(Groups and Ranges)</a></dt>
+ <dd>表示表达式字符的分组和范围。</dd>
+ <dt><a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Guide/Regular_Expressions/Quantifiers">量词(Quantifiers)</a></dt>
+ <dd>表示匹配的字符或表达式的数量。</dd>
+ <dt><a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Guide/Regular_Expressions/Unicode_Property_Escapes">Unicode 属性转义(Unicode Property Escapes)</a></dt>
+ <dd>基于 unicode 字符属性区分字符。例如大写和小写字母、数学符号和标点。</dd>
+</dl>
+
+<table class="standard-table">
+ <caption>正则表达式中的特殊字符</caption>
+ <thead>
+ <tr>
+ <th scope="col">字符</th>
+ <th scope="col">含义</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td><a href="#special-backslash" id="special-backslash" name="special-backslash"><code>\</code></a></td>
+ <td>
+ <p>依照下列规则匹配:</p>
+
+ <p>在非特殊字符之前的反斜杠表示下一个字符是特殊字符,不能按照字面理解。例如,前面没有 "\" 的 "b" 通常匹配小写字母 "b",即字符会被作为字面理解,无论它出现在哪里。但如果前面加了 "\",它将不再匹配任何字符,而是表示一个<a href="#note" title="#special-word-boundary">字符边界</a>。</p>
+
+ <p>在特殊字符之前的反斜杠表示下一个字符不是特殊字符,应该按照字面理解。详情请参阅下文中的 "转义(Escaping)" 部分。</p>
+
+ <p>如果你想将字符串传递给 RegExp 构造函数,不要忘记在字符串字面量中反斜杠是转义字符。所以为了在模式中添加一个反斜杠,你需要在字符串字面量中转义它。<code>/[a-z]\s/i</code> 和 <code>new RegExp("[a-z]\\s", "i")</code> 创建了相同的正则表达式:一个用于搜索后面紧跟着空白字符(<code>\s</code> 可看后文)并且在 a-z 范围内的任意字符的表达式。为了通过字符串字面量给 RegExp 构造函数创建包含反斜杠的表达式,你需要在字符串级别和正则表达式级别都对它进行转义。例如 <code>/[a-z]:\\/i</code> 和 <code>new RegExp("[a-z]:\\\\","i")</code> 会创建相同的表达式,即匹配类似 "C:\" 字符串。</p>
+ </td>
+ </tr>
+ <tr>
+ <td><a href="#special-caret" id="special-caret" name="special-caret"><code>^</code></a></td>
+ <td>
+ <p>匹配输入的开始。如果多行标志被设置为 true,那么也匹配换行符后紧跟的位置。</p>
+
+ <p>例如,<code>/^A/</code> 并不会匹配 "an A" 中的 'A',但是会匹配 "An E" 中的 'A'。</p>
+
+ <p>当 '<code>^</code>' 作为第一个字符出现在一个字符集合模式时,它将会有不同的含义。<a href="#special-negated-character-set">反向字符集合</a> 一节有详细介绍和示例。</p>
+ </td>
+ </tr>
+ <tr>
+ <td><a href="#special-dollar" id="special-dollar" name="special-dollar"><code>$</code></a></td>
+ <td>
+ <p>匹配输入的结束。如果多行标志被设置为 true,那么也匹配换行符前的位置。</p>
+
+ <p>例如,<code>/t$/</code> 并不会匹配 "eater" 中的 't',但是会匹配 "eat" 中的 't'。</p>
+ </td>
+ </tr>
+ <tr>
+ <td><a href="#special-asterisk" id="special-asterisk" name="special-asterisk"><code>*</code></a></td>
+ <td>
+ <p>匹配前一个表达式 0 次或多次。等价于 <code>{0,}</code>。</p>
+
+ <p>例如,<code>/bo*/</code> 会匹配 "A ghost boooooed" 中的 'booooo' 和 "A bird warbled" 中的 'b',但是在 "A goat grunted" 中不会匹配任何内容。</p>
+ </td>
+ </tr>
+ <tr>
+ <td><a href="#special-plus" id="special-plus" name="special-plus"><code>+</code></a></td>
+ <td>
+ <p>匹配前面一个表达式 1 次或者多次。等价于 <code>{1,}</code>。</p>
+
+ <p>例如,<code>/a+/</code> 会匹配 "candy" 中的 'a' 和 "caaaaaaandy" 中所有的 'a',但是在 "cndy" 中不会匹配任何内容。</p>
+ </td>
+ </tr>
+ <tr>
+ <td><a href="#special-questionmark" id="special-questionmark" name="special-questionmark"><code>?</code></a></td>
+ <td>
+ <p>匹配前面一个表达式 0 次或者 1 次。等价于 <code>{0,1}</code>。</p>
+
+ <p>例如,<code>/e?le?/</code> 匹配 "angel" 中的 'el'、"angle" 中的 'le' 以及 "oslo' 中的 'l'。</p>
+
+ <p>如果<strong>紧跟在任何量词 *、 +、? 或 {} 的后面</strong>,将会使量词变为<strong>非贪婪</strong>(匹配尽量少的字符),和缺省使用的<strong>贪婪模式</strong>(匹配尽可能多的字符)正好相反。例如,对 "123abc" 使用 <code>/\d+/</code> 将会匹配 "123",而使用 <code>/\d+?/</code> 则只会匹配到 "1"。</p>
+
+ <p>还用于先行断言中,如本表的 <code>x(?=y)</code> 和 <code>x(?!y)</code> 条目所述。</p>
+ </td>
+ </tr>
+ <tr>
+ <td><a href="#special-dot" id="special-dot" name="special-dot"><code>.</code></a></td>
+ <td>
+ <p>(小数点)默认匹配除换行符之外的任何单个字符。</p>
+
+ <p>例如,<code>/.n/</code> 将会匹配 "nay, an apple is on the tree" 中的 'an' 和 'on',但是不会匹配 'nay'。</p>
+
+ <p>如果 <code>s</code> ("dotAll") 标志位被设为 true,它也会匹配换行符。</p>
+ </td>
+ </tr>
+ <tr>
+ <td><a href="#special-capturing-parentheses" id="special-capturing-parentheses" name="special-capturing-parentheses"><code>(x)</code></a></td>
+ <td>
+ <p>像下面的例子展示的那样,它会匹配 'x' 并且记住匹配项。其中括号被称为<em>捕获括号</em>。</p>
+
+ <p>模式 <code>/(foo) (bar) \1 \2/</code> 中的 '<code>(foo)</code>' 和 '<code>(bar)</code>' 匹配并记住字符串 "foo bar foo bar" 中前两个单词。模式中的 <code>\1</code> 和 <code>\2</code> 表示第一个和第二个被捕获括号匹配的子字符串,即 <code>foo</code> 和 <code>bar</code>,匹配了原字符串中的后两个单词。注意 <code>\1</code>、<code>\2</code>、...、<code>\n</code> 是用在正则表达式的匹配环节,详情可以参阅后文的 <a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Guide/Regular_Expressions$edit#special-backreference">\n</a> 条目。而在正则表达式的替换环节,则要使用像 <code>$1</code>、<code>$2</code>、...、<code>$n</code> 这样的语法,例如,<code>'bar foo'.replace(/(...) (...)/, '$2 $1')</code>。<code>$&amp;</code> 表示整个用于匹配的原字符串。</p>
+ </td>
+ </tr>
+ <tr>
+ <td><a href="#special-non-capturing-parentheses" id="special-non-capturing-parentheses" name="special-non-capturing-parentheses"><code>(?:x)</code></a></td>
+ <td>
+ <p>匹配 'x' 但是不记住匹配项。这种括号叫作<em>非捕获括号</em>,使得你能够定义与正则表达式运算符一起使用的子表达式。看看这个例子 <code>/(?:foo){1,2}/</code>。如果表达式是 <code>/foo{1,2}/</code>,<code>{1,2}</code> 将只应用于 'foo' 的最后一个字符 'o'。如果使用非捕获括号,则 <code>{1,2}</code> 会应用于整个 'foo' 单词。更多信息,可以参阅下文的 <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#Using_parentheses">Using parentheses</a> 条目.</p>
+ </td>
+ </tr>
+ <tr>
+ <td><a href="#special-lookahead" id="special-lookahead" name="special-lookahead"><code>x(?=y)</code></a></td>
+ <td>
+ <p>匹配'x'仅仅当'x'后面跟着'y'.这种叫做先行断言。</p>
+
+ <p>例如,/Jack(?=Sprat)/会匹配到'Jack'仅当它后面跟着'Sprat'。/Jack(?=Sprat|Frost)/匹配‘Jack’仅当它后面跟着'Sprat'或者是‘Frost’。但是‘Sprat’和‘Frost’都不是匹配结果的一部分。</p>
+ </td>
+ </tr>
+ <tr>
+ <td><a href="#special-lookahead" id="special-lookahead" name="special-lookahead"><code>(?&lt;=y)</code></a>x</td>
+ <td>
+ <p>匹配'x'仅当'x'前面是'y'.这种叫做后行断言。</p>
+
+ <p>例如,/(?&lt;=Jack)Sprat/会匹配到' Sprat '仅仅当它前面是' Jack '。/(?&lt;=Jack|Tom)Sprat/匹配‘ Sprat ’仅仅当它前面是'Jack'或者是‘Tom’。但是‘Jack’和‘Tom’都不是匹配结果的一部分。</p>
+ </td>
+ </tr>
+ <tr>
+ <td><a href="#special-negated-look-ahead" id="special-negated-look-ahead" name="special-negated-look-ahead"><code>x(?!y)</code></a></td>
+ <td>
+ <p>仅仅当'x'后面不跟着'y'时匹配'x',这被称为正向否定查找。</p>
+
+ <p>例如,仅仅当这个数字后面没有跟小数点的时候,/\d+(?!\.)/ 匹配一个数字。正则表达式/\d+(?!\.)/.exec("3.141")匹配‘141’而不是‘3.141’</p>
+ </td>
+ </tr>
+ <tr>
+ <td><code>(?&lt;!<em>y</em>)<em>x</em></code></td>
+ <td>
+ <p>仅仅当'x'前面不是'y'时匹配'x',这被称为反向否定查找。</p>
+
+ <p>例如, 仅仅当这个数字前面没有负号的时候,<code>/(?&lt;!-)\d+/</code> 匹配一个数字。<br>
+ <code>/(?&lt;!-)\d+/.exec('3')</code> 匹配到 "3".<br>
+ <code>/(?&lt;!-)\d+/.exec('-3')</code> 因为这个数字前有负号,所以没有匹配到。</p>
+ </td>
+ </tr>
+ <tr>
+ <td><a href="#special-or" id="special-or" name="special-or"><code>x|y</code></a></td>
+ <td>
+ <p>匹配‘x’或者‘y’。</p>
+
+ <p>例如,/green|red/匹配“green apple”中的‘green’和“red apple”中的‘red’</p>
+ </td>
+ </tr>
+ <tr>
+ <td><a href="#special-quantifier" id="special-quantifier" name="special-quantifier"><code>{n}</code></a></td>
+ <td>n 是一个正整数,匹配了前面一个字符刚好出现了 n 次。<br>
+ 比如, /a{2}/ 不会匹配“candy”中的'a',但是会匹配“caandy”中所有的 a,以及“caaandy”中的前两个'a'。</td>
+ </tr>
+ <tr>
+ <td><a href="#special-quantifier" id="special-quantifier" name="special-quantifier"><code>{n,}</code></a></td>
+ <td>
+ <p>n是一个正整数,匹配前一个字符至少出现了n次。</p>
+
+ <p>例如, /a{2,}/ 匹配 "aa", "aaaa" 和 "aaaaa" 但是不匹配 "a"。</p>
+ </td>
+ </tr>
+ <tr>
+ <td><a href="#special-quantifier-range" id="special-quantifier-range" name="special-quantifier-range"><code>{n,m}</code></a></td>
+ <td>
+ <p>n 和 m 都是整数。匹配前面的字符至少n次,最多m次。如果 n 或者 m 的值是0, 这个值被忽略。</p>
+
+ <p>例如,/a{1, 3}/ 并不匹配“cndy”中的任意字符,匹配“candy”中的a,匹配“caandy”中的前两个a,也匹配“caaaaaaandy”中的前三个a。注意,当匹配”caaaaaaandy“时,匹配的值是“aaa”,即使原始的字符串中有更多的a。</p>
+ </td>
+ </tr>
+ <tr>
+ <td><a href="#special-character-set" id="special-character-set" name="special-character-set"><code>[xyz]</code></a></td>
+ <td>一个字符集合。匹配方括号中的任意字符,包括<a href="/zh-CN/docs/Web/JavaScript/Guide/Grammar_and_types">转义序列</a>。你可以使用破折号(-)来指定一个字符范围。对于点(.)和星号(*)这样的特殊符号在一个字符集中没有特殊的意义。他们不必进行转义,不过转义也是起作用的。<br>
+ 例如,[abcd] 和[a-d]是一样的。他们都匹配"brisket"中的‘b’,也都匹配“city”中的‘c’。/[a-z.]+/ 和/[\w.]+/与字符串“test.i.ng”匹配。</td>
+ </tr>
+ <tr>
+ <td><a href="#special-negated-character-set" id="special-negated-character-set" name="special-negated-character-set"><code>[^xyz]</code></a></td>
+ <td>
+ <p>一个反向字符集。也就是说, 它匹配任何没有包含在方括号中的字符。你可以使用破折号(-)来指定一个字符范围。任何普通字符在这里都是起作用的。</p>
+
+ <p>例如,[^abc] 和 [^a-c] 是一样的。他们匹配"brisket"中的‘r’,也匹配“chop”中的‘h’。</p>
+ </td>
+ </tr>
+ <tr>
+ <td><a href="#special-backspace" id="special-backspace" name="special-backspace"><code>[\b]</code></a></td>
+ <td>
+ <p>匹配一个退格(U+0008)。(不要和\b混淆了。)</p>
+ </td>
+ </tr>
+ <tr>
+ <td><a href="#special-word-boundary" id="special-word-boundary" name="special-word-boundary"><code>\b</code></a></td>
+ <td>
+ <p>匹配一个词的边界。一个词的边界就是一个词不被另外一个“字”字符跟随的位置或者前面跟其他“字”字符的位置,例如在字母和空格之间。注意,匹配中不包括匹配的字边界。换句话说,一个匹配的词的边界的内容的长度是0。(不要和[\b]混淆了)</p>
+
+ <p>使用"moon"举例:<br>
+ /\bm/匹配“moon”中的‘m’;<br>
+ /oo\b/并不匹配"moon"中的'oo',因为'oo'被一个“字”字符'n'紧跟着。<br>
+ /oon\b/匹配"moon"中的'oon',因为'oon'是这个字符串的结束部分。这样他没有被一个“字”字符紧跟着。<br>
+ /\w\b\w/将不能匹配任何字符串,因为在一个单词中间的字符永远也不可能同时满足没有“字”字符跟随和有“字”字符跟随两种情况。</p>
+
+ <div class="note">
+ <p><strong>注意:</strong> JavaScript的正则表达式引擎将<a href="http://www.ecma-international.org/ecma-262/5.1/#sec-15.10.2.6">特定的字符集</a>定义为“字”字符。不在该集合中的任何字符都被认为是一个断词。这组字符相当有限:它只包括大写和小写的罗马字母,十进制数字和下划线字符。不幸的是,重要的字符,例如“<a id="none" name="none"></a>é”或“ü”,被视为断词。</p>
+ </div>
+ </td>
+ </tr>
+ <tr>
+ <td><a href="#special-non-word-boundary" id="special-non-word-boundary" name="special-non-word-boundary"><code>\B</code></a></td>
+ <td>
+ <p>匹配一个非单词边界。匹配如下几种情况:</p>
+
+ <ul>
+ <li>字符串第一个字符为非“字”字符</li>
+ <li>字符串最后一个字符为非“字”字符</li>
+ <li>两个单词字符之间</li>
+ <li>两个非单词字符之间</li>
+ <li>空字符串</li>
+ </ul>
+
+ <p>例如,/\B../匹配"noonday"中的'oo', 而/y\B../匹配"possibly yesterday"中的’yes‘</p>
+ </td>
+ </tr>
+ <tr>
+ <td><a href="#special-control" id="special-control" name="special-control"><code>\c<em>X</em></code></a></td>
+ <td>
+ <p>当X是处于A到Z之间的字符的时候,匹配字符串中的一个控制符。</p>
+
+ <p>例如,<code>/\cM/</code> 匹配字符串中的 control-M (U+000D)。</p>
+ </td>
+ </tr>
+ <tr>
+ <td><a href="#special-digit" id="special-digit" name="special-digit"><code>\d</code></a></td>
+ <td>
+ <p>匹配一个数字<code>。</code><code>等价于[0-9]</code>。</p>
+
+ <p>例如, <code>/\d/</code> 或者 <code>/[0-9]/</code> 匹配"B2 is the suite number."中的'2'。</p>
+ </td>
+ </tr>
+ <tr>
+ <td><a href="#special-non-digit" id="special-non-digit" name="special-non-digit"><code>\D</code></a></td>
+ <td>
+ <p>匹配一个非数字字符<code>。</code><code>等价于[^0-9]</code>。</p>
+
+ <p>例如, <code>/\D/</code> 或者 <code>/[^0-9]/</code> 匹配"B2 is the suite number."中的'B' 。</p>
+ </td>
+ </tr>
+ <tr>
+ <td><a href="#special-form-feed" id="special-form-feed" name="special-form-feed"><code>\f</code></a></td>
+ <td>匹配一个换页符 (U+000C)。</td>
+ </tr>
+ <tr>
+ <td><a href="#special-line-feed" id="special-line-feed" name="special-line-feed"><code>\n</code></a></td>
+ <td>匹配一个换行符 (U+000A)。</td>
+ </tr>
+ <tr>
+ <td><a href="#special-carriage-return" id="special-carriage-return" name="special-carriage-return"><code>\r</code></a></td>
+ <td>匹配一个回车符 (U+000D)。</td>
+ </tr>
+ <tr>
+ <td><a href="#special-white-space" id="special-white-space" name="special-white-space"><code>\s</code></a></td>
+ <td>
+ <p>匹配一个空白字符,包括空格、制表符、换页符和换行符。等价于[ \f\n\r\t\v\u00a0\u1680\u180e\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff]。</p>
+
+ <p>例如, <code>/\s\w*/</code> 匹配"foo bar."中的' bar'。</p>
+
+ <p>经测试,\s不匹配"<a href="https://unicode-table.com/cn/180E/">\u180e</a>",在当前版本Chrome(v80.0.3987.122)和Firefox(76.0.1)控制台输入/\s/.test("\u180e")均返回false。</p>
+ </td>
+ </tr>
+ <tr>
+ <td><a href="#special-non-white-space" id="special-non-white-space" name="special-non-white-space"><code>\S</code></a></td>
+ <td>
+ <p>匹配一个非空白字符。等价于 <code>[^ </code>\f\n\r\t\v\u00a0\u1680\u180e\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff<code>]</code>。</p>
+
+ <p>例如,<code>/\S\w*/</code> 匹配"foo bar."中的'foo'。</p>
+ </td>
+ </tr>
+ <tr>
+ <td><a href="#special-tab" id="special-tab" name="special-tab"><code>\t</code></a></td>
+ <td>匹配一个水平制表符 (U+0009)。</td>
+ </tr>
+ <tr>
+ <td><a href="#special-vertical-tab" id="special-vertical-tab" name="special-vertical-tab"><code>\v</code></a></td>
+ <td>匹配一个垂直制表符 (U+000B)。</td>
+ </tr>
+ <tr>
+ <td><a href="#special-word" id="special-word" name="special-word"><code>\w</code></a></td>
+ <td>
+ <p>匹配一个单字字符(字母、数字或者下划线)。等价于 <code>[A-Za-z0-9_]</code>。</p>
+
+ <p>例如, <code>/\w/</code> 匹配 "apple," 中的 'a',"$5.28,"中的 '5' 和 "3D." 中的 '3'。</p>
+ </td>
+ </tr>
+ <tr>
+ <td><a href="#special-non-word" id="special-non-word" name="special-non-word"><code>\W</code></a></td>
+ <td>
+ <p>匹配一个非单字字符。等价于 <code>[^A-Za-z0-9_]</code>。</p>
+
+ <p>例如, <code>/\W/</code> 或者 <code>/[^A-Za-z0-9_]/</code> 匹配 "50%." 中的 '%'。</p>
+ </td>
+ </tr>
+ <tr>
+ <td><a href="#special-backreference" id="special-backreference" name="special-backreference"><code>\<em>n</em></code></a></td>
+ <td>
+ <p>在正则表达式中,它返回最后的第n个子捕获匹配的子字符串(捕获的数目以左括号计数)。</p>
+
+ <p>比如 <code>/apple(,)\sorange\1/</code> 匹配"apple, orange, cherry, peach."中的'apple, orange,' 。</p>
+ </td>
+ </tr>
+ <tr>
+ <td><a href="#special-null" id="special-null" name="special-null"><code>\0</code></a></td>
+ <td>匹配 NULL(U+0000)字符, 不要在这后面跟其它小数,因为 <code>\0&lt;digits&gt;</code> 是一个八进制转义序列。</td>
+ </tr>
+ <tr>
+ <td><a href="#special-hex-escape" id="special-hex-escape" name="special-hex-escape"><code>\xhh</code></a></td>
+ <td>匹配一个两位十六进制数(\x00-\xFF)表示的字符。</td>
+ </tr>
+ <tr>
+ <td><a href="#special-unicode-escape" id="special-unicode-escape" name="special-unicode-escape"><code>\uhhhh</code></a></td>
+ <td>匹配一个四位十六进制数表示的 UTF-16 代码单元。</td>
+ </tr>
+ <tr>
+ <td>
+ <p><code><a href="#special-unicode-escape-es6" id="special-unicode-escape-es6" name="special-unicode-escape-es6">\u{hhhh}</a>或\u{hhhhh}</code></p>
+ </td>
+ <td>(仅当设置了u标志时)匹配一个十六进制数表示的 Unicode 字符。</td>
+ </tr>
+ </tbody>
+</table>
+
+<h3 id="Escaping">Escaping</h3>
+
+<p>如果你需要使用任何特殊字符的字面值(例如,搜索字符'*'),你必须通过在它前面放一个反斜杠来转义它。 例如,要搜索'a'后跟'*'后跟'b',你应该使用<code>/a\*b/</code>- 反斜杠“转义”字符'*',使其成为文字而非特殊符号。</p>
+
+<p>类似地,如果您正在编写正则表达式文字并且需要匹配斜杠('/'),那么需要转义它(否则,斜杠是正则终止符)。 例如,要搜索字符串“/ example /”后跟一个或多个字母字符,您需要使用<code>/\/example\/[a-z]+/i</code>——每个斜杠之前使用反斜杠使它们成为普通字符。</p>
+
+<p>要匹配文本符号反斜杠,您需要转义反斜杠。 例如,要匹配字符串“C:\”,其中“C”可以是任何字母,您将使用<code>/[A-Z]:\\/</code> —— 第一个反斜杠转义后面的那个反斜杠,因此表达式搜索单个普通字符反斜杠。</p>
+
+<p>如果将RegExp构造函数与字符串文字一起使用,请记住反斜杠是字符串文字中的转义,因此要在正则表达式中使用它,您需要在字符串文字级别转义它。 <code>/a\*b/</code> 和<code>new RegExp("a\\*b")</code>创建的表达式是相同的,搜索“a”后跟文字“*”后跟“b”。</p>
+
+<p>将用户输入转义为正则表达式中的一个字面字符串, 可以通过简单的替换来实现:</p>
+
+<pre class="brush: js notranslate">function escapeRegExp(string) {
+ return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&amp;");
+ //$&amp;表示整个被匹配的字符串
+}</pre>
+
+<p>正则表达式后的"g"是一个表示全局搜索选项或标记,将在整个字符串查找并返回所有匹配结果。这将在下面的<a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Guide/Regular_Expressions#%E9%80%9A%E8%BF%87%E6%A0%87%E5%BF%97%E8%BF%9B%E8%A1%8C%E9%AB%98%E7%BA%A7%E6%90%9C%E7%B4%A2">通过标志进行高级搜索</a>详述。</p>
+
+<p>为什么这个没有内建在JavaScript中?之前有计划在RegExp对象中添加一个Function,但在<a href="https://github.com/benjamingr/RegExp.escape/issues/37">TC39</a>中被否决了。</p>
+
+<h3 id="使用插入语">使用插入语</h3>
+
+<p>任何正则表达式的插入语都会使这部分匹配的副字符串被记忆。一旦被记忆,这个副字符串就可以被调用于其它用途,如同 <a href="#使用括号的子字符串匹配">使用括号的子字符串匹配</a>之中所述。</p>
+
+<p>比如, <code>/Chapter (\d+)\.\d*/</code> 解释了额外转义的和特殊的字符,并说明了这部分pattern应该被记忆。它精确地匹配后面跟着一个以上数字字符的字符 'Chapter ' (<code>\d</code> 意为任何数字字符,<code>+ 意为1次以上</code>),跟着一个小数点(在这个字符中本身也是一个特殊字符;小数点前的 \ 意味着这个pattern必须寻找字面字符 '.'),跟着任何数字字符0次以上。 (<code>\d</code> 意为数字字符, <code>*</code> 意为0次以上)。另外,插入语也用来记忆第一个匹配的数字字符。</p>
+
+<p>此模式可以匹配字符串"Open Chapter 4.3, paragraph 6",并且'4'将会被记住。此模式并不能匹配"Chapter 3 and 4",因为在这个字符串中'3'的后面没有点号'.'。</p>
+
+<p>括号中的"?:",这种模式匹配的子字符串将不会被记住。比如,(?:\d+)匹配一次或多次数字字符,但是不能记住匹配的字符。</p>
+
+<h2 id="使用正则表达式">使用正则表达式</h2>
+
+<p>正则表达式可以被用于 <code><a href="/zh-CN/docs/JavaScript/Reference/Global_Objects/RegExp">RegExp</a></code> 的 <a href="/zh-CN/docs/JavaScript/Reference/Global_Objects/RegExp/exec"><code>exec</code></a> 和 <a href="/zh-CN/docs/JavaScript/Reference/Global_Objects/RegExp/test"><code>test</code></a> 方法以及 <a href="/zh-CN/docs/JavaScript/Reference/Global_Objects/String"><code>String</code></a> 的 <a href="/zh-CN/docs/JavaScript/Reference/Global_Objects/String/match"><code>match</code></a>、<a href="/zh-CN/docs/JavaScript/Reference/Global_Objects/String/replace"><code>replace</code></a>、<a href="/zh-CN/docs/JavaScript/Reference/Global_Objects/String/search"><code>search</code></a> 和 <a href="/zh-CN/docs/JavaScript/Reference/Global_Objects/String/split"><code>split</code></a> 方法。这些方法在 <a href="/zh-CN/docs/JavaScript/Reference">JavaScript 手册</a>中有详细的解释。</p>
+
+<table class="standard-table">
+ <caption>使用正则表达式的方法</caption>
+ <thead>
+ <tr>
+ <th scope="col">方法</th>
+ <th scope="col">描述</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>{{jsxref("RegExp.exec", "exec")}}</td>
+ <td>一个在字符串中执行查找匹配的RegExp方法,它返回一个数组(未匹配到则返回 null)。</td>
+ </tr>
+ <tr>
+ <td>{{jsxref("RegExp.test", "test")}}</td>
+ <td>一个在字符串中测试是否匹配的RegExp方法,它返回 true 或 false。</td>
+ </tr>
+ <tr>
+ <td>{{jsxref("String.match", "match")}}</td>
+ <td>一个在字符串中执行查找匹配的String方法,它返回一个数组,在未匹配到时会返回 null。</td>
+ </tr>
+ <tr>
+ <td>{{jsxref("String.matchAll", "matchAll")}}</td>
+ <td>一个在字符串中执行查找所有匹配的String方法,它返回一个迭代器(iterator)。</td>
+ </tr>
+ <tr>
+ <td>{{jsxref("String.search", "search")}}</td>
+ <td>一个在字符串中测试匹配的String方法,它返回匹配到的位置索引,或者在失败时返回-1。</td>
+ </tr>
+ <tr>
+ <td>{{jsxref("String.replace", "replace")}}</td>
+ <td>一个在字符串中执行查找匹配的String方法,并且使用替换字符串替换掉匹配到的子字符串。</td>
+ </tr>
+ <tr>
+ <td>{{jsxref("String.split", "split")}}</td>
+ <td>一个使用正则表达式或者一个固定字符串分隔一个字符串,并将分隔后的子字符串存储到数组中的 <code>String</code> 方法。</td>
+ </tr>
+ </tbody>
+</table>
+
+<p>当你想要知道在一个字符串中的一个匹配是否被找到,你可以使用 test 或 search 方法;想得到更多的信息(但是比较慢)则可以使用 exec 或 match 方法。如果你使用exec 或 match 方法并且匹配成功了,那么这些方法将返回一个数组并且更新相关的正则表达式对象的属性和预定义的正则表达式对象(详见下)。如果匹配失败,那么 exec 方法返回 null(也就是false)。</p>
+
+<p>在接下来的例子中,脚本将使用exec方法在一个字符串中查找一个匹配。</p>
+
+<pre class="brush: js notranslate">var myRe = /d(b+)d/g;
+var myArray = myRe.exec("cdbbdbsbz");
+</pre>
+
+<p>如果你不需要访问正则表达式的属性,这个脚本通过另一个方法来创建myArray:</p>
+
+<pre class="brush: js notranslate">var myArray = /d(b+)d/g.exec("cdbbdbsbz");
+// 和 "cdbbdbsbz".match(/d(b+)d/g); 相似。
+// 但是 "cdbbdbsbz".match(/d(b+)d/g) 输出数组 [ "dbbd" ],
+// 而 /d(b+)d/g.exec('cdbbdbsbz') 输出数组 [ "dbbd", "bb", index: 1, input: "cdbbdbsbz" ].
+
+</pre>
+
+<p>如果你想通过一个字符串构建正则表达式,那么这个脚本还有另一种方法:</p>
+
+<pre class="brush: js notranslate">var myRe = new RegExp("d(b+)d", "g");
+var myArray = myRe.exec("cdbbdbsbz");
+</pre>
+
+<p>通过这些脚本,匹配成功后将返回一个数组并且更新正则表达式的属性,如下表所示。</p>
+
+<table class="standard-table">
+ <caption>正则表达式执行后的返回信息</caption>
+ <thead>
+ <tr>
+ <th scope="col">对象</th>
+ <th scope="col">属性或索引</th>
+ <th scope="col">描述</th>
+ <th scope="col">在例子中对应的值</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td rowspan="4"><code>myArray</code></td>
+ <td></td>
+ <td>匹配到的字符串和所有被记住的子字符串。</td>
+ <td><code>["dbbd", "bb"]</code></td>
+ </tr>
+ <tr>
+ <td><code>index</code></td>
+ <td>在输入的字符串中匹配到的以0开始的索引值。</td>
+ <td><code>1</code></td>
+ </tr>
+ <tr>
+ <td><code>input</code></td>
+ <td>初始字符串。</td>
+ <td><code>"cdbbdbsbz"</code></td>
+ </tr>
+ <tr>
+ <td><code>[0]</code></td>
+ <td>最近一个匹配到的字符串。</td>
+ <td><code>"dbbd"</code></td>
+ </tr>
+ <tr>
+ <td rowspan="2"><code>myRe</code></td>
+ <td><code>lastIndex</code></td>
+ <td>开始下一个匹配的起始索引值。(这个属性只有在使用g参数时可用在 <a href="/zh-CN/docs/Web/JavaScript/Guide/Regular_Expressions#.E9.80.9A.E8.BF.87.E5.8F.82.E6.95.B0.E8.BF.9B.E8.A1.8C.E9.AB.98.E7.BA.A7.E6.90.9C.E7.B4.A2">通过参数进行高级搜索</a> 一节有详细的描述.)</td>
+ <td><code>5</code></td>
+ </tr>
+ <tr>
+ <td><code>source</code></td>
+ <td>模式字面文本。在正则表达式创建时更新,不执行。</td>
+ <td><code>"d(b+)d"</code></td>
+ </tr>
+ </tbody>
+</table>
+
+<p>如这个例子中的第二种形式所示,你可以使用对象初始器创建一个正则表达式实例,但不分配给变量。如果你这样做,那么,每一次使用时都会创建一个新的正则表达式实例。因此,如果你不把正则表达式实例分配给一个变量,你以后将不能访问这个正则表达式实例的属性。例如,假如你有如下脚本:</p>
+
+<pre class="brush: js notranslate">var myRe = /d(b+)d/g;
+var myArray = myRe.exec("cdbbdbsbz");
+console.log("The value of lastIndex is " + myRe.lastIndex);
+</pre>
+
+<p>这个脚本输出如下:</p>
+
+<pre class="notranslate">The value of lastIndex is 5
+</pre>
+
+<p>然而,如果你有如下脚本:</p>
+
+<pre class="brush: js notranslate">var myArray = /d(b+)d/g.exec("cdbbdbsbz");
+console.log("The value of lastIndex is " + /d(b+)d/g.lastIndex);
+</pre>
+
+<p>它显示为:</p>
+
+<pre class="notranslate">The value of lastIndex is 0
+</pre>
+
+<p>当发生/d(b+)d/g使用两个不同状态的正则表达式对象,lastIndex属性会得到不同的值。如果你需要访问一个正则表达式的属性,则需要创建一个对象初始化生成器,你应该首先把它赋值给一个变量。</p>
+
+<h3 id="使用括号的子字符串匹配_2"><a id="使用括号的子字符串匹配" name="使用括号的子字符串匹配">使用括号的子字符串匹配</a></h3>
+
+<p>一个正则表达式模式使用括号,将导致相应的子匹配被记住。例如,/a(b)c /可以匹配字符串“abc”,并且记得“b”。回调这些括号中匹配的子串,使用数组元素[1],……[n]。</p>
+
+<p>使用括号匹配的子字符串的数量是无限的。返回的数组中保存所有被发现的子匹配。下面的例子说明了如何使用括号的子字符串匹配。</p>
+
+<p>下面的脚本使用replace()方法来转换字符串中的单词。在匹配到的替换文本中,脚本使用替代的$ 1,$ 2表示第一个和第二个括号的子字符串匹配。</p>
+
+<pre class="brush: js notranslate">var re = /(\w+)\s(\w+)/;
+var str = "John Smith";
+var newstr = str.replace(re, "$2, $1");
+console.log(newstr);
+</pre>
+
+<p>这个表达式输出 "Smith, John"。</p>
+
+<h3 id="通过标志进行高级搜索">通过标志进行高级搜索</h3>
+
+<p>正则表达式有六个可选参数 (<code>flags</code>) 允许全局和不分大小写搜索等。这些参数既可以单独使用也能以任意顺序一起使用, 并且被包含在正则表达式实例中。</p>
+
+<table class="standard-table">
+ <caption>正则表达式标志</caption>
+ <thead>
+ <tr>
+ <th scope="col" style="white-space: nowrap;">标志</th>
+ <th scope="col" style="white-space: nowrap;">描述</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td style="text-align: center;"><code>g</code></td>
+ <td>全局搜索。</td>
+ </tr>
+ <tr>
+ <td style="text-align: center;"><code>i</code></td>
+ <td>不区分大小写搜索。</td>
+ </tr>
+ <tr>
+ <td style="text-align: center;"><code>m</code></td>
+ <td>多行搜索。</td>
+ </tr>
+ <tr>
+ <td style="text-align: center;"><code>s</code></td>
+ <td>允许 <code>.</code> 匹配换行符。</td>
+ </tr>
+ <tr>
+ <td style="text-align: center;"><code>u</code></td>
+ <td>使用unicode码的模式进行匹配。</td>
+ </tr>
+ <tr>
+ <td style="text-align: center;"><code>y</code></td>
+ <td>执行“粘性(<code>sticky</code>)”搜索,匹配从目标字符串的当前位置开始。</td>
+ </tr>
+ </tbody>
+</table>
+
+<p>为了在正则表达式中包含标志,请使用以下语法:</p>
+
+<pre class="brush: js notranslate">var re = /pattern/flags;
+</pre>
+
+<p>或者</p>
+
+<pre class="brush: js notranslate">var re = new RegExp("pattern", "flags");
+</pre>
+
+<p>值得注意的是,标志是一个正则表达式的一部分,它们在接下来的时间将不能添加或删除。</p>
+
+<p>例如,re = /\w+\s/g 将创建一个查找一个或多个字符后有一个空格的正则表达式,或者组合起来像此要求的字符串。</p>
+
+<pre class="brush: js notranslate">var re = /\w+\s/g;
+var str = "fee fi fo fum";
+var myArray = str.match(re);
+console.log(myArray);
+
+// ["fee ", "fi ", "fo "]
+</pre>
+
+<p>这段代码将输出 ["fee ", "fi ", "fo "]。在这个例子中,你可以将:</p>
+
+<pre class="brush: js notranslate">var re = /\w+\s/g;
+</pre>
+
+<p>替换成:</p>
+
+<pre class="brush: js notranslate">var re = new RegExp("\\w+\\s", "g");
+</pre>
+
+<p>并且能获取到相同的结果。</p>
+
+<p>使用<code>.exec()</code>方法时,与'<code>g</code>'标志关联的行为是不同的。 (“class”和“argument”的作用相反:在<code>.match()</code>的情况下,字符串类(或数据类型)拥有该方法,而正则表达式只是一个参数,而在<code>.exec()</code>的情况下,它是拥有该方法的正则表达式,其中字符串是参数。对比<em><code>str.match(re)</code></em>与<em><code>re.exec(str)</code></em> ), '<code>g</code>'标志与<code>.exec()</code>方法一起使用获得迭代进展。</p>
+
+<pre class="brush: js notranslate">var xArray; while(xArray = re.exec(str)) console.log(xArray);
+// produces:
+// ["fee ", index: 0, input: "fee fi fo fum"]
+// ["fi ", index: 4, input: "fee fi fo fum"]
+// ["fo ", index: 7, input: "fee fi fo fum"]</pre>
+
+<p>m标志用于指定多行输入字符串应该被视为多个行。如果使用m标志,^和$匹配的开始或结束输入字符串中的每一行,而不是整个字符串的开始或结束。</p>
+
+<h2 id="例子">例子</h2>
+
+<p>以下例子说明了一些正则表达式的用途。</p>
+
+<h3 id="改变输入字符串的顺序">改变输入字符串的顺序</h3>
+
+<p>以下例子解释了正则表达式的构成和 <code>string.split()</code> 以及 <code>string.replace()</code>的用途。它会整理一个只有粗略格式的含有全名(名字首先出现)的输入字符串,这个字符串被空格、换行符和一个分号分隔。最终,它会颠倒名字顺序(姓氏首先出现)和list的类型。</p>
+
+<pre class="brush: js notranslate">// 下面这个姓名字符串包含了多个空格和制表符,
+// 且在姓和名之间可能有多个空格和制表符。
+var names = "Orange Trump ;Fred Barney; Helen Rigby ; Bill Abel ; Chris Hand ";
+
+var output = ["---------- Original String\n", names + "\n"];
+
+// 准备两个模式的正则表达式放进数组里。
+// 分割该字符串放进数组里。
+
+// 匹配模式:匹配一个分号及紧接其前后所有可能出现的连续的不可见符号。
+var pattern = /\s*;\s*/;
+
+// 把通过上述匹配模式分割的字符串放进一个叫做nameList的数组里面。
+var nameList = names.split(pattern);
+
+// 新建一个匹配模式:匹配一个或多个连续的不可见字符及其前后紧接着由
+// 一个或多个连续的基本拉丁字母表中的字母、数字和下划线组成的字符串
+// 用一对圆括号来捕获该模式中的一部分匹配结果。
+// 捕获的结果稍后会用到。
+pattern = /(\w+)\s+(\w+)/;
+
+// 新建一个数组 bySurnameList 用来临时存放正在处理的名字。
+var bySurnameList = [];
+
+// 输出 nameList 的元素并且把 nameList 里的名字
+// 用逗号接空格的模式把姓和名分割开来然后存放进数组 bySurnameList 中。
+//
+// 下面的这个替换方法把 nameList 里的元素用 $2, $1 的模式
+// (第二个捕获的匹配结果紧接着一个逗号一个空格然后紧接着第一个捕获的匹配结果)替换了
+// 变量 $1 和变量 $2 是上面所捕获的匹配结果。
+
+output.push("---------- After Split by Regular Expression");
+
+var i, len;
+for (i = 0, len = nameList.length; i &lt; len; i++) {
+ output.push(nameList[i]);
+ bySurnameList[i] = nameList[i].replace(pattern, "$2, $1");
+}
+
+// 输出新的数组
+output.push("---------- Names Reversed");
+for (i = 0, len = bySurnameList.length; i &lt; len; i++){
+ output.push(bySurnameList[i]);
+}
+
+// 根据姓来排序,然后输出排序后的数组。
+bySurnameList.sort();
+output.push("---------- Sorted");
+for (i = 0, len = bySurnameList.length; i &lt; len; i++){
+ output.push(bySurnameList[i]);
+}
+
+output.push("---------- End");
+
+console.log(output.join("\n"));
+</pre>
+
+<h3 id="用特殊字符检验输入">用特殊字符检验输入</h3>
+
+<p>在以下例子中,我们期望用户输入一个电话号码。当用户点击“Check”按钮,我们的脚本开始检查这些数字是否合法。如果数字合法(匹配正则表达式所规定的字符序列),脚本显示一条感谢用户的信息并确认该数字。如果这串数字不合法,脚本提示用户电话号码不合法。.</p>
+
+<p>包含非捕获括号 <code>(?:</code> 这个正则表达式寻找三个数字字符<code>\d{3}</code> 或者 <code>|</code> 一个左半括号<code>\(</code>跟着三位数字<code>\d{3}</code>, 跟着一个封闭括号 <code>\)</code>, (结束非捕获括号 <code>)</code>), 后跟着一个短破折号或正斜杠或小数点,随后跟随三个数字字符,当记忆字符 <code>([-\/\.])捕获并记住,后面跟着三位小数</code> <code>\d{3},再后面跟随记住的破折号、正斜杠或小数点</code> <code>\1,最后跟着四位小数</code> <code>\d{4}。</code></p>
+
+<p>当用户按下 Enter 设置 RegExp.input,这些变化也能被激活。</p>
+
+<pre class="brush: html notranslate">&lt;!DOCTYPE html&gt;
+&lt;html&gt;
+ &lt;head&gt;
+ &lt;meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"&gt;
+ &lt;meta http-equiv="Content-Script-Type" content="text/javascript"&gt;
+ &lt;script type="text/javascript"&gt;
+ var re = /(?:\d{3}|\(\d{3}\))([-\/\.])\d{3}\1\d{4}/;
+ function testInfo(phoneInput) {
+ var OK = re.exec(phoneInput.value);
+ if (!OK)
+ window.alert(phoneInput.value + ' isn\'t a phone number with area code!');
+ else
+ window.alert('Thanks, your phone number is ' + OK[0]);
+ }
+ &lt;/script&gt;
+ &lt;/head&gt;
+ &lt;body&gt;
+ &lt;p&gt;Enter your phone number (with area code) and then click "Check".
+ &lt;br&gt;The expected format is like ###-###-####.&lt;/p&gt;
+ &lt;form action="#"&gt;
+ &lt;input id="phone"&gt;&lt;button onclick="testInfo(document.getElementById('phone'));"&gt;Check&lt;/button&gt;
+ &lt;/form&gt;
+ &lt;/body&gt;
+&lt;/html&gt;
+</pre>
+
+<div>{{PreviousNext("Web/JavaScript/Guide/Text_formatting", "Web/JavaScript/Guide/Indexed_collections")}}</div>
diff --git a/files/zh-cn/web/javascript/guide/regular_expressions/unicode_property_escapes/index.html b/files/zh-cn/web/javascript/guide/regular_expressions/unicode_property_escapes/index.html
new file mode 100644
index 0000000000..0b0252022a
--- /dev/null
+++ b/files/zh-cn/web/javascript/guide/regular_expressions/unicode_property_escapes/index.html
@@ -0,0 +1,171 @@
+---
+title: Unicode property escapes
+slug: Web/JavaScript/Guide/Regular_Expressions/Unicode_Property_Escapes
+translation_of: Web/JavaScript/Guide/Regular_Expressions/Unicode_Property_Escapes
+---
+<p>{{jsSidebar("JavaScript Guide")}}</p>
+
+<p><strong>Unicode property escapes</strong> <a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Guide/Regular_Expressions">正则表达式</a> 支持根据 Unicode 属性进行匹配,例如我们可以用它来匹配出表情、标点符号、字母(甚至适用特定语言或文字)等。同一符号可以拥有多种 Unicode 属性,属性则有 binary ("boolean-like") 和 non-binary 之分。</p>
+
+<div>{{EmbedInteractiveExample("pages/js/regexp-unicode-property-escapes.html", "taller")}}</div>
+
+<div class="blockIndicator note">
+<p><strong>Note: </strong>使用 Unicode 属性转义依靠 <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/unicode"><code>\u</code> 标识</a>,<code>\u</code> 表示该字符串被视为一串 Unicode 代码点。参考 <code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/unicode">RegExp.prototype.nicode</a></code>.</p>
+</div>
+
+<div class="blockIndicator note">
+<p><strong>Note:</strong> 某些 Unicode 属性比<a href="/en-US/docs/Web/JavaScript/Guide/Regular_Expressions/Character_Classes">字符类</a>(如 <code>\w</code> 只匹配拉丁字母 <code>a</code> 到 <code>z</code>)包含更多的字符  ,但后者浏览器兼容性更好 (截至2020 一月).</p>
+</div>
+
+<h2 id="句法">句法</h2>
+
+<div class="hidden">The following section is also duplicated on <a href="/en-US/docs/Web/JavaScript/Guide/Regular_Expressions/Cheatsheet">this cheatsheet</a>. Do not forget to edit it as well, thanks!</div>
+
+<pre class="brush: js notranslate">// Non-binary 属性
+\p{<em>Unicode属性值</em>}
+\p{<em>Unicode属性名</em>=<em>Unicode属性值</em>}
+
+// Binary and non-binary 属性
+\p{<em>UnicodeBinary属性名</em>}
+
+// \P 为 \p 取反
+\P{<em>Unicode属性值</em>}
+\P{<em>UnicodeBinary属性名</em>}
+</pre>
+
+<ul>
+ <li><a href="https://unicode.org/reports/tr18/#General_Category_Property">General_Category</a> (<code>gc</code>)</li>
+ <li><a href="https://unicode.org/reports/tr24/#Script">Script</a> (<code>sc</code>)</li>
+ <li><a href="https://unicode.org/reports/tr24/#Script_Extensions">Script_Extensions</a> (<code>scx</code>)</li>
+</ul>
+
+<p>参考 <a href="https://www.unicode.org/Public/UCD/latest/ucd/PropertyValueAliases.txt">PropertyValueAliases.txt<span style="display: none;"> </span></a></p>
+
+<dl>
+ <dt>UnicodeBinary属性名</dt>
+ <dd><a href="https://tc39.es/ecma262/#table-binary-unicode-properties">Binary 属性</a>名. E.g.: <code><a href="https://unicode.org/reports/tr18/#General_Category_Property">ASCII</a></code>. <code><a href="https://unicode.org/reports/tr44/#Alphabetic">Alpha</a></code>, <code>Math</code>, <code><a href="https://unicode.org/reports/tr44/#Diacritic">Diacritic</a></code>, <code><a href="https://unicode.org/reports/tr51/#Emoji_Properties">Emoji</a></code>, <code><a href="https://unicode.org/reports/tr44/#Hex_Digit">Hex_Digit</a></code>, <code>Math</code>, <code><a href="https://unicode.org/reports/tr44/#White_Space">White_space</a></code>, 等. 另见 <a href="https://www.unicode.org/Public/UCD/latest/ucd/PropList.txt">Unicode Data PropList.txt</a>.</dd>
+ <dt>Unicode属性名</dt>
+ <dd><a href="https://tc39.es/ecma262/#table-nonbinary-unicode-properties">Non-binary</a> 属性名:</dd>
+ <dt>Unicode属性值</dt>
+ <dd>很多值有同名或简写(e.g. 对应着 <code>General_Category</code> 属性名的属性值 <code>Decimal_Number</code> 可以写作 <code>Nd</code>, <code>digit</code>, 或 <code>Decimal_Number</code>). 大多数属性值的 <em><code>Unicode属性名</code></em> 和等号可以省去。如果想明确某 <em><code>Unicode属性名</code></em>,必须给出它的值。</dd>
+</dl>
+
+<div class="blockIndicator note">
+<p><strong>Note:</strong> 因为可使用的属性和值太多,这里不一一赘述,仅提供几个例子。</p>
+</div>
+
+<h2 id="基本原理">基本原理</h2>
+
+<p>在 ES2018 之前,JavaScript 没有强有效的方式用匹配出不同<code>文字</code>(如马其顿语,希腊语,Georgian 等)或不同 <code>属性名</code> (如 Emoji 等)的字符。另见 <a href="https://github.com/tc39/proposal-regexp-unicode-property-escapes">tc39 Proposal on Unicode Property Escapes</a>.</p>
+
+<h2 id="例子">例子</h2>
+
+<h3 id="(一般类别)General_categories">(一般类别)General categories</h3>
+
+<p>General categories 对 Unicode 字符进行分类,子类别用于精确定义类别。长名和简写的 Unicode 属性转义都可用.</p>
+
+<p>它们可匹配字母、数字、符号、标点符号、空格等等。一般类别详见 <a href="https://unicode.org/reports/tr18/#General_Category_Property">the Unicode specification</a>.</p>
+
+<pre class="brush: js notranslate">// finding all the letters of a text
+let story = "It’s the Cheshire Cat: now I shall have somebody to talk to.";
+
+// Most explicit form
+story.match(/\p{General_Category=Letter}/gu);
+
+// It is not mandatory to use the property name for General categories
+story.match(/\p{Letter}/gu);
+
+// This is equivalent (short alias):
+story.match(/\p{L}/gu);
+
+// This is also equivalent (conjunction of all the subcategories using short aliases)
+story.match(/\p{Lu}|\p{Ll}|\p{Lt}|\p{Lm}|\p{Lo}/gu);
+</pre>
+
+<h3 id="文字(Script)和文字扩充(Script_Extensions)">文字(Script)和文字扩充(Script_Extensions)</h3>
+
+<p>某些语言使用不同的文字,如英语和西班牙语使用拉丁文,而阿拉伯语和俄语用阿拉伯文和俄文。<code>Script</code> 和 <code>Script_Extensions</code> Unicode 属性允许正则表达式根据字符所属的<code>文字</code>或该文字所属的<code>文字扩充</code>进行匹配。</p>
+
+<p>比如,<code>A</code> 属于 <code>拉丁文</code>,<code>ε</code> 属于<code>希腊(Greek)</code>文。</p>
+
+<pre class="brush: js notranslate">let mixedCharacters = "aεЛ";
+
+// Using the canonical "long" name of the script
+mixedCharacters.match(/\p{Script=Latin}/u); // a
+
+// Using a short alias for the script
+mixedCharacters.match(/\p{Script=Grek}/u); // ε
+
+// Using the short name Sc for the Script property
+mixedCharacters.match(/\p{Sc=Cyrillic}/u); // Л
+</pre>
+
+<p>详见 <a href="https://unicode.org/reports/tr24/#Script">the Unicode specification</a> 和 <a href="https://tc39.es/ecma262/#table-unicode-script-values">Scripts table in the ECMAScript specification</a>.</p>
+
+<p>某字符用于多种文字时,<code>Script</code> 优先匹配最主要使用那个字符的文字。如果想要根据非主要的文字进行匹配,我们可以使用 <code>Script_Extensions</code> 属性 (简写为<code>Scx</code>).</p>
+
+<pre class="brush: js notranslate">// ٢ is the digit 2 in Arabic-Indic notation
+// while it is predominantly written within the Arabic script
+// it can also be written in the Thaana script
+
+"٢".match(/\p{Script=Thaana}/u);
+// null as Thaana is not the predominant script        super()
+
+"٢".match(/\p{Script_Extensions=Thaana}/u);
+// ["٢", index: 0, input: "٢", groups: undefined]
+</pre>
+
+<h3 id="Unicode_属性转义_vs._字符类">Unicode 属性转义 vs. 字符类</h3>
+
+<p>JavaScript 正则表达式可以使用 <a href="/en-US/docs/Web/JavaScript/Guide/Regular_Expressions/Character_Classes">字符类</a> 尤其是 <code>\w</code> 或 <code>\d</code> 匹配字母或数字,然而,这样的形式只匹配拉丁文字的字符 (换言之,<code>a</code> 到 <code>z</code>、 <code>A</code> 到 <code>Z</code> 的 <code>\w</code> 和 <code>0</code> 到 <code>9</code> 的 <code>\d</code>),见<a href="/en-US/docs/Web/JavaScript/Guide/Regular_Expressions/Character_Classes#Looking_for_a_word_from_Unicode_characters">例子</a>,这样的使用放到非拉丁文本中是有些蠢的。</p>
+
+<p>Unicode 属性转义 categories 包含更多字符, <code>\p{Letter}</code> 或 <code>\p{Number}</code> 将会适用于任何文字。</p>
+
+<pre class="brush: js notranslate">// Trying to use ranges to avoid \w limitations:
+
+const nonEnglishText = "Приключения Алисы в Стране чудес";
+const regexpBMPWord = /([\u0000-\u0019\u0021-\uFFFF])+/gu;
+// BMP goes through U+0000 to U+FFFF but space is U+0020
+
+console.table(nonEnglishText.match(regexpBMPWord));
+
+// Using Unicode property escapes instead
+const regexpUPE = /\p{L}+/gu;
+console.table(nonEnglishText.match(regexpUPE));
+</pre>
+
+<h2 id="Specifications">Specifications</h2>
+
+<table class="standard-table">
+ <tbody>
+ <tr>
+ <th scope="col">Specification</th>
+ </tr>
+ <tr>
+ <td>{{SpecName('ESDraft', '#sec-runtime-semantics-unicodematchproperty-p', 'RegExp: Unicode property escapes')}}</td>
+ </tr>
+ </tbody>
+</table>
+
+<h2 id="Browser_compatibility">Browser compatibility</h2>
+
+<p>For browser compatibility information, check out the <a href="/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#Browser_compatibility">main Regular Expressions compatibility table</a>.</p>
+
+<h2 id="See_also">See also</h2>
+
+<ul>
+ <li><a href="/en-US/docs/Web/JavaScript/Guide/Regular_Expressions">Regular expressions guide</a>
+
+ <ul>
+ <li><a href="/en-US/docs/Web/JavaScript/Guide/Regular_Expressions/Character_Classes">Character classes</a></li>
+ <li><a href="/en-US/docs/Web/JavaScript/Guide/Regular_Expressions/Assertions">Assertions</a></li>
+ <li><a href="/en-US/docs/Web/JavaScript/Guide/Regular_Expressions/Quantifiers">Quantifiers</a></li>
+ <li><a href="/en-US/docs/Web/JavaScript/Guide/Regular_Expressions/Groups_and_Ranges">Groups and ranges</a></li>
+ </ul>
+ </li>
+ <li><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp">The <code>RegExp()</code> constructor</a></li>
+ <li><code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/unicode">RegExp.prototype.unicode</a></code></li>
+ <li><a href="https://en.wikipedia.org/wiki/Unicode_character_property">Unicode character property — Wikipedia</a></li>
+ <li><a href="https://2ality.com/2017/07/regexp-unicode-property-escapes.html">A blog post from Axel Rauschmayer about Unicode property escapes</a></li>
+ <li><a href="https://unicode.org/reports/tr18/#Categories">The Unicode document for Unicode properties</a></li>
+</ul>
diff --git a/files/zh-cn/web/javascript/guide/regular_expressions/量词/index.html b/files/zh-cn/web/javascript/guide/regular_expressions/量词/index.html
new file mode 100644
index 0000000000..bcc2a35e13
--- /dev/null
+++ b/files/zh-cn/web/javascript/guide/regular_expressions/量词/index.html
@@ -0,0 +1,170 @@
+---
+title: 量词
+slug: Web/JavaScript/Guide/Regular_Expressions/量词
+translation_of: Web/JavaScript/Guide/Regular_Expressions/Quantifiers
+---
+<p>{{jsSidebar("JavaScript Guide")}}</p>
+
+<p>量词表示要匹配的字符或表达式的数量。</p>
+
+<div>{{EmbedInteractiveExample("pages/js/regexp-quantifiers.html", "taller")}}</div>
+
+<h2 id="类型">类型</h2>
+
+<div class="hidden">The following table is also duplicated on <a href="/en-US/docs/Web/JavaScript/Guide/Regular_Expressions/Cheatsheet">this cheatsheet</a>. Do not forget to edit it as well, thanks!</div>
+
+<table class="standard-table">
+ <thead>
+ <tr>
+ <th scope="col">Characters</th>
+ <th scope="col">Meaning</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td><code><em>x</em>*</code></td>
+ <td>
+ <p>将前面的项“x”匹配0次或更多次。例如,/bo*/匹配“A ghost booooed”中的“boooo”和“A bird warbled”中的“b”,但在“A goat grunt”中没有匹配。</p>
+ </td>
+ </tr>
+ <tr>
+ <td><code><em>x</em>+</code></td>
+ <td>
+ <p>将前一项“x”匹配1次或更多次。等价于{1,}。例如,/a+/匹配“candy”中的“a”和“caaaaaaandy”中的“a”。</p>
+ </td>
+ </tr>
+ <tr>
+ <td><code><em>x</em>?</code></td>
+ <td>
+ <p>将前面的项“x”匹配0或1次。例如,/ e ?勒?/匹配angel中的el和angle中的le。</p>
+
+ <p>如果立即在任何量词*、+、?或{}之后使用,则使量词是非贪婪的(匹配最小次数),而不是默认的贪婪的(匹配最大次数)。</p>
+ </td>
+ </tr>
+ <tr>
+ <td><code><em>x</em>{<em>n</em>}</code></td>
+ <td>
+ <p>其中“n”是一个正整数,与前一项“x”的n次匹配。例如,<code>/a{2}/ </code>不匹配“candy”中的“a”,但它匹配“caandy”中的所有“a”,以及“caaandy”中的前两个“a”。</p>
+ </td>
+ </tr>
+ <tr>
+ <td><code><em>x</em>{<em>n</em>,}</code></td>
+ <td>
+ <p>其中,“n”是一个正整数,与前一项“x”至少匹配“n”次。例如,<code>/a{2,}/</code>不匹配“candy”中的“a”,但匹配“caandy”和“caaaaaaandy”中的所有a。</p>
+ </td>
+ </tr>
+ <tr>
+ <td><code><em>x</em>{<em>n</em>,<em>m</em>}</code></td>
+ <td>
+ <p>其中,“n”是0或一个正整数,“m”是一个正整数,而m &gt; n至少与前一项“x”匹配,最多与“m”匹配。例如,/a{1,3}/不匹配“cndy”中的“a”,“candy”中的“a”,“caandy”中的两个“a”,以及“caaaaaaandy”中的前三个“a”。注意,当匹配“caaaaaaandy”时,匹配的是“aaa”,即使原始字符串中有更多的“a”。</p>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <p><code><em>x</em>*?</code><br>
+ <code><em>x</em>+?</code><br>
+ <code><em>x</em>??</code><br>
+ <code><em>x</em>{n}?</code><br>
+ <code><em>x</em>{n,}?</code><br>
+ <code><em>x</em>{n,m}?</code></p>
+ </td>
+ <td>
+ <p>默认情况下,像 <code>* </code>和 <code>+ </code>这样的量词是“贪婪的”,这意味着它们试图匹配尽可能多的字符串。?量词后面的字符使量词“非贪婪”:意思是它一旦找到匹配就会停止。例如,给定一个字符串“some &lt;foo&gt; &lt;bar&gt; new &lt;/bar&gt; &lt;/foo&gt; thing”:</p>
+
+ <ul>
+ <li><code>/&lt;.*&gt;/</code> will match "&lt;foo&gt; &lt;bar&gt; new &lt;/bar&gt; &lt;/foo&gt;"</li>
+ <li><code>/&lt;.*?&gt;/</code> will match "&lt;foo&gt;"</li>
+ </ul>
+ </td>
+ </tr>
+ </tbody>
+</table>
+
+<h2 id="举例说明">举例说明</h2>
+
+<h3 id="重复模式">重复模式</h3>
+
+<pre class="brush: js notranslate">var wordEndingWithAs = /\w+a+/;
+var delicateMessage = "This is Spartaaaaaaa";
+
+console.table(delicateMessage.match(wordEndingWithAs)); // [ "Spartaaaaaaa" ]</pre>
+
+<h3 id="计算字符集">计算字符集</h3>
+
+<pre class="brush: js notranslate">var singleLetterWord = /\b\w\b/g;
+var notSoLongWord = /\b\w{1,6}\b/g;
+var loooongWord = /\b\w{13,}\b/g;
+
+var sentence = "Why do I have to learn multiplication table?";
+
+console.table(sentence.match(singleLetterWord)); // ["I"]
+console.table(sentence.match(notSoLongWord)); // <span class="message-body-wrapper"><span class="message-flex-body"><span class="devtools-monospace message-body"><span class="objectBox objectBox-array"><span class="arrayLeftBracket">[ </span><span class="objectBox objectBox-string">"Why"</span>, <span class="objectBox objectBox-string">"do"</span>, <span class="objectBox objectBox-string">"I"</span>, <span class="objectBox objectBox-string">"have"</span>, <span class="objectBox objectBox-string">"to"</span>, <span class="objectBox objectBox-string">"learn"</span>, <span class="objectBox objectBox-string">"table"</span><span class="arrayRightBracket"> ]</span></span></span></span></span>
+console.table(sentence.match(loooongWord)); // ["multiplication"]可选可选字符
+</pre>
+
+<h3 id="可选字符"> 可选字符</h3>
+
+<pre class="brush: js notranslate">var britishText = "He asked his neighbour a favour.";
+var americanText = "He asked his neighbor a favor.";
+
+var regexpEnding = /\w+ou?r/g;
+// \w+ One or several letters
+// o followed by an "o",
+// u? optionally followed by a "u"
+// r followed by an "r"
+
+console.table(britishText.match(regexpEnding));
+// ["neighbour", "favour"]
+
+console.table(americanText.match(regexpEnding));
+// ["neighbor", "favor"]
+</pre>
+
+<h3 id="贪婪_与_非贪婪的">贪婪 与 非贪婪的</h3>
+
+<pre class="brush: js notranslate">var text = "I must be getting somewhere near the centre of the earth.";
+var greedyRegexp = /[\w ]+/;
+// [\w ] a letter of the latin alphabet or a whitespace
+// + one or several times
+
+console.log(text.match(greedyRegexp)[0]);
+// "I must be getting somewhere near the centre of the earth"
+// almost all of the text matches (leaves out the dot character)
+
+var nonGreedyRegexp = /[\w ]+?/; // Notice the question mark
+console.log(text.match(nonGreedyRegexp));
+// "I"
+// The match is the smallest one possible
+</pre>
+
+<h2 id="规范"><strong>规范</strong></h2>
+
+<table class="standard-table">
+ <tbody>
+ <tr>
+ <th scope="col">Specification</th>
+ </tr>
+ <tr>
+ <td>{{SpecName('ESDraft', '#sec-quantifier', 'RegExp: Quantifiers')}}</td>
+ </tr>
+ </tbody>
+</table>
+
+<h2 id="浏览器支持">浏览器支持</h2>
+
+<p>For browser compatibility information, check out the <a href="/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#Browser_compatibility">main Regular Expressions compatibility table</a>.</p>
+
+<h2 id="See_also">See also</h2>
+
+<ul>
+ <li><a href="/en-US/docs/Web/JavaScript/Guide/Regular_Expressions">Regular expressions guide</a>
+
+ <ul>
+ <li><a href="/en-US/docs/Web/JavaScript/Guide/Regular_Expressions/Character_Classes">Character classes</a></li>
+ <li><a href="/en-US/docs/Web/JavaScript/Guide/Regular_Expressions/Assertions">Assertions</a></li>
+ <li><a href="/en-US/docs/Web/JavaScript/Guide/Regular_Expressions/Unicode_Property_Escapes">Unicode property escapes</a></li>
+ <li><a href="/en-US/docs/Web/JavaScript/Guide/Regular_Expressions/Groups_and_Ranges">Groups and ranges</a></li>
+ </ul>
+ </li>
+ <li><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp">The <code>RegExp()</code> constructor</a></li>
+</ul>
diff --git a/files/zh-cn/web/javascript/guide/text_formatting/index.html b/files/zh-cn/web/javascript/guide/text_formatting/index.html
new file mode 100644
index 0000000000..71d93dfe78
--- /dev/null
+++ b/files/zh-cn/web/javascript/guide/text_formatting/index.html
@@ -0,0 +1,252 @@
+---
+title: Text formatting
+slug: Web/JavaScript/Guide/Text_formatting
+tags:
+ - Guide
+ - JavaScript
+translation_of: Web/JavaScript/Guide/Text_formatting
+---
+<div>{{jsSidebar("JavaScript Guide")}} {{PreviousNext("Web/JavaScript/Guide/Numbers_and_dates", "Web/JavaScript/Guide/Regular_Expressions")}}</div>
+
+<p class="summary">本章介绍在Javascript中如何使用字符串与文本内容。</p>
+
+<h2 id="字符串">字符串</h2>
+
+<p>JavaScript中的 {{Glossary("String")}} 类型用于表示文本型的数据. 它是由无符号整数值(16bit)作为元素而组成的集合. 字符串中的每个元素在字符串中占据一个位置. 第一个元素的index值是0, 下一个元素的index值是1, 以此类推. 字符串的长度就是字符串中所含的元素个数.你可以通过String字面值或者String对象两种方式创建一个字符串。</p>
+
+<h3 id="String字面量">String字面量</h3>
+
+<p>可以使用单引号或双引号创建简单的字符串:</p>
+
+<pre class="brush: js notranslate">'foo'
+"bar"</pre>
+
+<p>可以使用转义序列来创建更复杂的字符串:</p>
+
+<h4 id="16进制转义序列">16进制转义序列</h4>
+
+<p>\x之后的数值将被认为是一个16进制数.</p>
+
+<pre class="brush: js notranslate">'\xA9' // "©"
+</pre>
+
+<h4 id="Unicode转义序列">Unicode转义序列</h4>
+
+<p>Unicode转义序列在\u之后需要至少4个字符.</p>
+
+<pre class="brush: js notranslate">'\u00A9' // "©"</pre>
+
+<h4 id="Unicode字元逸出">Unicode字元逸出</h4>
+
+<p>这是ECMAScript 6中的新特性。有了Unicode字元逸出,任何字符都可以用16进制数转义, 这使得通过Unicode转义表示大于<code>0x10FFFF</code>的字符成为可能。使用简单的Unicode转义时通常需要分别写字符相应的两个部分(译注:大于<span style="font-family: courier,andale mono,monospace;">0x10FFFF的字符需要拆分为相应的两个小于0x10FFFF的部分</span>)来达到同样的效果。</p>
+
+<p>请参阅 {{jsxref("String.fromCodePoint()")}} 或 {{jsxref("String.prototype.codePointAt()")}}。</p>
+
+<pre class="brush: js notranslate">'\u{2F804}'
+
+// the same with simple Unicode escapes
+'\uD87E\uDC04'</pre>
+
+<h3 id="字符串对象">字符串对象</h3>
+
+<p>{{jsxref("String")}} 对象是对原始string类型的封装 .</p>
+
+<pre class="notranslate">const foo = new String('foo'); // 创建一个 String 对象
+console.log(foo); // 输出: [String: 'foo']
+typeof foo; // 返回 'object'</pre>
+
+<p>你可以在String字面值上使用String对象的任何方法—JavaScript自动把String字面值转换为一个临时的String对象, 然后调用其相应方法,最后丢弃此临时对象.在String字面值上也可以使用String.length属性.</p>
+
+<p>除非必要, 应该尽量使用 String 字面值,因为String对象的某些行为可能并不与直觉一致。举例:</p>
+
+<pre class="notranslate">const firstString = '2 + 2'; //创建一个字符串字面量
+const secondString = new String('2 + 2'); // 创建一个字符串对象
+eval(firstString); // 返回数字 4
+eval(secondString); // 返回字符串 "2 + 2"</pre>
+
+<p><code>String</code> 对象有一个属性 <code>length</code>,标识了字符串中 UTF-16 的码点个数。举例,下面的代码把 13 赋值给了<code>helloLength</code>,因为 "Hello, World!" 包含 13 个字符,每个字符用一个 UTF-16 码点表示。你可以通过数组的方式访问每一个码点,但你不能修改每个字符,因为字符串是不变的类数组对象: </p>
+
+<pre class="notranslate">const hello = 'Hello, World!';
+const helloLength = hello.length;
+hello[0] = 'L'; // 无效,因为字符串是不变的
+hello[0]; // 返回 "H"</pre>
+
+<p>Characters whose Unicode scalar values are greater than U+FFFF (such as some rare Chinese/Japanese/Korean/Vietnamese characters and some emoji) are stored in UTF-16 with two surrogate code units each. For example, a string containing the single character U+1F600 "Emoji grinning face" will have length 2. Accessing the individual code units in such a string using brackets may have undesirable consequences such as the formation of strings with unmatched surrogate code units, in violation of the Unicode standard. (Examples should be added to this page after MDN bug 857438 is fixed.) See also {{jsxref("String.fromCodePoint()")}} or {{jsxref("String.prototype.codePointAt()")}}.</p>
+
+<p><code>String</code>对象有许多方法: 举例来说有些方法返回字符串本身的变体, 如 <code>substring</code> 和<code>toUpperCase</code>.</p>
+
+<p>下表总结了 {{jsxref("String")}} 对象的方法.</p>
+
+<table class="standard-table">
+ <caption>
+ <h4 id="String对象方法">String对象方法</h4>
+ </caption>
+ <thead>
+ <tr>
+ <th scope="col">方法</th>
+ <th scope="col">描述</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>{{jsxref("String.charAt", "charAt")}}, {{jsxref("String.charCodeAt", "charCodeAt")}}, {{jsxref("String.codePointAt", "codePointAt")}}</td>
+ <td>返回字符串指定位置的字符或者字符编码。</td>
+ </tr>
+ <tr>
+ <td>{{jsxref("String.indexOf", "indexOf")}}, {{jsxref("String.lastIndexOf", "lastIndexOf")}}</td>
+ <td>分别返回字符串中指定子串的位置或最后位置。</td>
+ </tr>
+ <tr>
+ <td>{{jsxref("String.startsWith", "startsWith")}}, {{jsxref("String.endsWith", "endsWith")}}, {{jsxref("String.includes", "includes")}}</td>
+ <td>返回字符串是否以指定字符串开始、结束或包含指定字符串。</td>
+ </tr>
+ <tr>
+ <td>{{jsxref("String.concat", "concat")}}</td>
+ <td>连接两个字符串并返回新的字符串。</td>
+ </tr>
+ <tr>
+ <td>{{jsxref("String.fromCharCode", "fromCharCode")}}, {{jsxref("String.fromCodePoint", "fromCodePoint")}}</td>
+ <td>从指定的Unicode值序列构造一个字符串。这是一个String类方法,不是实例方法。</td>
+ </tr>
+ <tr>
+ <td>{{jsxref("String.split", "split")}}</td>
+ <td>通过将字符串分离成一个个子串来把一个String对象分裂到一个字符串数组中。</td>
+ </tr>
+ <tr>
+ <td>{{jsxref("String.slice", "slice")}}</td>
+ <td>从一个字符串提取片段并作为新字符串返回。</td>
+ </tr>
+ <tr>
+ <td>{{jsxref("String.substring", "substring")}}, {{jsxref("String.substr", "substr")}}</td>
+ <td>分别通过指定起始和结束位置,起始位置和长度来返回字符串的指定子集。</td>
+ </tr>
+ <tr>
+ <td>{{jsxref("String.match", "match")}}, {{jsxref("String.replace", "replace")}}, {{jsxref("String.search", "search")}}</td>
+ <td>通过正则表达式来工作.</td>
+ </tr>
+ <tr>
+ <td>{{jsxref("String.toLowerCase", "toLowerCase")}}, {{jsxref("String.toUpperCase", "toUpperCase")}}</td>
+ <td>
+ <p>分别返回字符串的小写表示和大写表示。</p>
+ </td>
+ </tr>
+ <tr>
+ <td>{{jsxref("String.normalize", "normalize")}}</td>
+ <td>按照指定的一种 Unicode 正规形式将当前字符串正规化。</td>
+ </tr>
+ <tr>
+ <td>{{jsxref("String.repeat", "repeat")}}</td>
+ <td>将字符串内容重复指定次数后返回。</td>
+ </tr>
+ <tr>
+ <td>{{jsxref("String.trim", "trim")}}</td>
+ <td>去掉字符串开头和结尾的空白字符。</td>
+ </tr>
+ </tbody>
+</table>
+
+<h3 id="多行模板字符串">多行模板字符串</h3>
+
+<p>模板字符串是一种允许内嵌表达式的String字面值. 可以用它实现多行字符串或者字符串内插等特性.</p>
+
+<p>模板字符串使用反勾号 (` `) (<a class="external external-icon" href="https://en.wikipedia.org/wiki/Grave_accent">grave accent</a>) 包裹内容而不是单引号或双引号. 模板字符串可以包含占位符. 占位符用美元符号和花括号标识 (<code>${expression}</code>).</p>
+
+<h4 id="多行">多行</h4>
+
+<p>源代码中插入的任何新行开始字符都作为模板字符串的内容. 使用一般的字符串时, 为了创建多行的字符串不得不用如下语法:</p>
+
+<pre class="brush: js notranslate">console.log("string text line 1\n\
+string text line 2");
+// "string text line 1
+// string text line 2"</pre>
+
+<p>为了实现同样效果的多行字符串, 现在可以写成如下形式:</p>
+
+<pre class="brush: js notranslate">console.log(`string text line 1
+string text line 2`);
+// "string text line 1
+// string text line 2"</pre>
+
+<h4 id="嵌入表达式">嵌入表达式</h4>
+
+<p>为了在一般的字符串中嵌入表达式, 需要使用如下语法:</p>
+
+<pre class="notranslate">const five = 5;
+const ten = 10;
+console.log('Fifteen is ' + (five + ten) + ' and not ' + (2 * five + ten) + '.');
+// "Fifteen is 15 and not 20."</pre>
+
+<p>现在, 使用模板字符串, 可以使用语法糖让类似功能的实现代码更具可读性:</p>
+
+<pre class="notranslate">const five = 5;
+const ten = 10;
+console.log(`Fifteen is ${five + ten} and not ${2 * five + ten}.`);
+// "Fifteen is 15 and not 20."</pre>
+
+<p>更多信息, 请阅读 <a href="/en-US/docs/Web/JavaScript/Reference">JavaScript reference</a> 中的 <a href="/en-US/docs/Web/JavaScript/Reference/template_strings">Template strings</a>。</p>
+
+<h2 id="国际化">国际化</h2>
+
+<p>{{jsxref("Intl")}} 对象是ECMAScript国际化API的命名空间, 它提供了语言敏感的字符串比较,数字格式化和日期时间格式化功能.  {{jsxref("Collator")}}, {{jsxref("NumberFormat")}}, 和 {{jsxref("DateTimeFormat")}} 对象的构造函数是<code>Intl</code>对象的属性.</p>
+
+<h3 id="日期和时间格式化">日期和时间格式化</h3>
+
+<p>{{jsxref("DateTimeFormat")}} 对象在日期和时间的格式化方面很有用. 下面的代码把一个日期格式化为美式英语格式. (不同时区结果不同.)</p>
+
+<pre class="brush: js notranslate">const msPerDay = 24 * 60 * 60 * 1000;
+
+// July 17, 2014 00:00:00 UTC.
+const july172014 = new Date(msPerDay * (44 * 365 + 11 + 197));//2014-1970=44年
+//这样创建日期真是醉人。。。还要自己计算天数。。。11是闰年中多出的天数。。。
+//197是6×30+16(7月的16天)+3(3个大月)-2(2月少2天)
+
+const options = { year: "2-digit", month: "2-digit", day: "2-digit",
+    hour: "2-digit", minute: "2-digit", timeZoneName: "short" };
+const americanDateTime = new Intl.DateTimeFormat("en-US", options).format;
+
+console.log(americanDateTime(july172014)); // 07/16/14, 5:00 PM PDT
+</pre>
+
+<h3 id="数字格式化">数字格式化</h3>
+
+<p>{{jsxref("NumberFormat")}} 对象在数字的格式化方面很有用, 比如货币数量值.</p>
+
+<pre class="brush: js notranslate">var gasPrice = new Intl.NumberFormat("en-US",
+                        { style: "currency", currency: "USD",
+                          minimumFractionDigits: 3 });
+
+console.log(gasPrice.format(5.259)); // $5.259
+
+var hanDecimalRMBInChina = new Intl.NumberFormat("zh-CN-u-nu-hanidec",
+                        { style: "currency", currency: "CNY" });
+
+console.log(hanDecimalRMBInChina.format(1314.25)); // ¥ 一,三一四.二五
+</pre>
+
+<h3 id="定序">定序</h3>
+
+<p>{{jsxref("Collator")}} 对象在字符串比较和排序方面很有用.</p>
+
+<p>举例, 德语中<em>有两种不同的排序方式 电话本(phonebook)</em> 和 字典(<em>dictionary)</em>. 电话本排序强调发音, 比如在排序前 “ä”, “ö”等被扩展为 “ae”, “oe”等发音.</p>
+
+<pre class="brush: js notranslate">var names = ["Hochberg", "Hönigswald", "Holzman"];
+
+var germanPhonebook = new Intl.Collator("de-DE-u-co-phonebk");
+
+// as if sorting ["Hochberg", "Hoenigswald", "Holzman"]:
+console.log(names.sort(germanPhonebook.compare).join(", "));
+// logs "Hochberg, Hönigswald, Holzman"
+</pre>
+
+<p>有些德语词包含变音, 所以在字典中忽略变音进行排序是合理的 (除非待排序的单词只有变音部分不同: <em>schon</em> 先于 <em>schön</em>).</p>
+
+<pre class="brush: js notranslate">var germanDictionary = new Intl.Collator("de-DE-u-co-dict");
+
+// as if sorting ["Hochberg", "Honigswald", "Holzman"]:
+console.log(names.sort(germanDictionary.compare).join(", "));
+// logs "Hochberg, Holzman, Hönigswald"
+</pre>
+
+<p>关于{{jsxref("Intl")}} API的更多信息, 请参考 <a href="https://hacks.mozilla.org/2014/12/introducing-the-javascript-internationalization-api/">Introducing the JavaScript Internationalization API</a>。</p>
+
+<div>{{PreviousNext("Web/JavaScript/Guide/Numbers_and_dates", "Web/JavaScript/Guide/Regular_Expressions")}}</div>
diff --git a/files/zh-cn/web/javascript/guide/using_promises/index.html b/files/zh-cn/web/javascript/guide/using_promises/index.html
new file mode 100644
index 0000000000..c714260d7f
--- /dev/null
+++ b/files/zh-cn/web/javascript/guide/using_promises/index.html
@@ -0,0 +1,359 @@
+---
+title: 使用 Promise
+slug: Web/JavaScript/Guide/Using_promises
+tags:
+ - Guide
+ - JavaScript
+ - Promise
+ - 中级
+ - 异步
+ - 指南
+translation_of: Web/JavaScript/Guide/Using_promises
+---
+<div>{{jsSidebar("JavaScript Guide")}}{{PreviousNext("Web/JavaScript/Guide/Details_of_the_Object_Model", "Web/JavaScript/Guide/Iterators_and_Generators")}}</div>
+
+<p>{{jsxref("Promise")}} 是一个对象,它代表了一个异步操作的最终完成或者失败。因为大多数人仅仅是使用已创建的 Promise 实例对象,所以本教程将首先说明怎样使用 Promise,再说明如何创建 Promise。</p>
+
+<p>本质上 Promise 是一个函数返回的对象,我们可以在它上面绑定回调函数,这样我们就不需要在一开始把回调函数作为参数传入这个函数了。</p>
+
+<p>假设现在有一个名为 <code>createAudioFileAsync()</code> 的函数,它接收一些配置和两个回调函数,然后异步地生成音频文件。一个回调函数在文件成功创建时被调用,另一个则在出现异常时被调用。</p>
+
+<p>以下为使用 <code>createAudioFileAsync()</code> 的示例:</p>
+
+<pre class="brush: js notranslate">// 成功的回调函数
+function successCallback(result) {
+ console.log("音频文件创建成功: " + result);
+}
+
+// 失败的回调函数
+function failureCallback(error) {
+ console.log("音频文件创建失败: " + error);
+}
+
+createAudioFileAsync(audioSettings, successCallback, failureCallback)</pre>
+
+<p>更现代的函数会返回一个 Promise 对象,使得你可以将你的回调函数绑定在该 Promise 上。</p>
+
+<p>如果函数 <code>createAudioFileAsync()</code> 被重写为返回 Promise 的形式,那么我们可以像下面这样简单地调用它:</p>
+
+<pre class="brush: js line-numbers language-js notranslate">const promise = createAudioFileAsync(audioSettings);
+promise.then(successCallback, failureCallback);
+</pre>
+
+<p>或者简写为:</p>
+
+<pre class="brush: js line-numbers language-js notranslate">createAudioFileAsync(audioSettings).then(successCallback, failureCallback);
+</pre>
+
+<p>我们把这个称为 <em>异步函数调用</em>,这种形式有若干优点,下面我们将会逐一讨论。</p>
+
+<h2 id="约定">约定</h2>
+
+<p>不同于“老式”的传入回调,在使用 Promise 时,会有以下约定:</p>
+
+<ul>
+ <li>在本轮 <a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/EventLoop#执行至完成">事件循环</a> 运行完成之前,回调函数是不会被调用的。</li>
+ <li>即使异步操作已经完成(成功或失败),在这之后通过 <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/then"><code>then()</code> </a>添加的回调函数也会被调用。</li>
+ <li>通过多次调用 <code><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/then">then()</a></code> 可以添加多个回调函数,它们会按照插入顺序进行执行。</li>
+</ul>
+
+<p>Promise 很棒的一点就是<strong>链式调用</strong>(<strong>chaining</strong>)。</p>
+
+<h2 id="链式调用">链式调用</h2>
+
+<p>连续执行两个或者多个异步操作是一个常见的需求,在上一个操作执行成功之后,开始下一个的操作,并带着上一步操作所返回的结果。我们可以通过创造一个 <strong>Promise 链</strong>来实现这种需求。</p>
+
+<p>见证奇迹的时刻:<code>then()</code> 函数会返回一个和原来不同的<strong>新的 Promise</strong>:</p>
+
+<pre class="brush: js line-numbers language-js notranslate">const promise = doSomething();
+const promise2 = promise.then(successCallback, failureCallback);
+</pre>
+
+<p>或者</p>
+
+<pre class="brush: js notranslate">const promise2 = doSomething().then(successCallback, failureCallback);</pre>
+
+<p><code>promise2</code> 不仅表示 <code>doSomething()</code> 函数的完成,也代表了你传入的 <code>successCallback</code> 或者 <code>failureCallback</code> 的完成,这两个函数也可以返回一个 Promise 对象,从而形成另一个异步操作,这样的话,在 <code>promise2</code> 上新增的回调函数会排在这个 Promise 对象的后面。</p>
+
+<p>基本上,每一个 Promise 都代表了链中另一个异步过程的完成。</p>
+
+<p>在过去,要想做多重的异步操作,会导致经典的回调地狱:</p>
+
+<pre class="brush: js notranslate">doSomething(function(result) {
+ doSomethingElse(result, function(newResult) {
+ doThirdThing(newResult, function(finalResult) {
+ console.log('Got the final result: ' + finalResult);
+ }, failureCallback);
+ }, failureCallback);
+}, failureCallback);
+</pre>
+
+<p>现在,我们可以把回调绑定到返回的 Promise 上,形成一个 Promise 链:</p>
+
+<pre class="brush: js notranslate">doSomething().then(function(result) {
+ return doSomethingElse(result);
+})
+.then(function(newResult) {
+ return doThirdThing(newResult);
+})
+.then(function(finalResult) {
+ console.log('Got the final result: ' + finalResult);
+})
+.catch(failureCallback);
+</pre>
+
+<p>then 里的参数是可选的,<code>catch(failureCallback)</code> 是 <code>then(null, failureCallback)</code> 的缩略形式。如下所示,我们也可以用<a href="/zh-CN/docs/Web/JavaScript/Reference/Functions/Arrow_functions">箭头函数</a>来表示:</p>
+
+<pre class="brush: js notranslate">doSomething()
+.then(result =&gt; doSomethingElse(result))
+.then(newResult =&gt; doThirdThing(newResult))
+.then(finalResult =&gt; {
+ console.log(`Got the final result: ${finalResult}`);
+})
+.catch(failureCallback);
+</pre>
+
+<p><strong>注意:</strong>一定要有返回值,否则,callback 将无法获取上一个 Promise 的结果。(如果使用箭头函数,<code>() =&gt; x</code> 比 <code>() =&gt; { return x; }</code> 更简洁一些,但后一种保留 <code>return</code> 的写法才支持使用多个语句。)。</p>
+
+<h3 id="Catch_的后续链式操作">Catch 的后续链式操作</h3>
+
+<p>有可能会在一个回调失败之后继续使用链式操作,即,使用一个 <code>catch</code>,这对于在链式操作中抛出一个失败之后,再次进行新的操作会很有用。请阅读下面的例子:</p>
+
+<pre class="brush: js notranslate">new Promise((resolve, reject) =&gt; {
+ console.log('初始化');
+
+ resolve();
+})
+.then(() =&gt; {
+ throw new Error('有哪里不对了');
+
+ console.log('执行「这个」”');
+})
+.catch(() =&gt; {
+ console.log('执行「那个」');
+})
+.then(() =&gt; {
+ console.log('执行「这个」,无论前面发生了什么');
+});
+</pre>
+
+<p>输出结果如下:</p>
+
+<pre class="notranslate">初始化
+执行“那个”
+执行“这个”,无论前面发生了什么
+</pre>
+
+<p><strong>注意:</strong>因为抛出了错误 <u>有哪里不对了</u>,所以前一个 <u>执行「这个」</u> 没有被输出。</p>
+
+<h2 id="错误传递">错误传递</h2>
+
+<p>在之前的回调地狱示例中,你可能记得有 3 次 <code>failureCallback</code> 的调用,而在 Promise 链中只有尾部的一次调用。</p>
+
+<pre class="brush: js notranslate">doSomething()
+.then(result =&gt; doSomethingElse(result))
+.then(newResult =&gt; doThirdThing(newResult))
+.then(finalResult =&gt; console.log(`Got the final result: ${finalResult}`))
+.catch(failureCallback);
+
+</pre>
+
+<p>通常,一遇到异常抛出,浏览器就会顺着 Promise 链寻找下一个 <code>onRejected</code> 失败回调函数或者由 <code>.catch()</code> 指定的回调函数。这和以下同步代码的工作原理(执行过程)非常相似。</p>
+
+<pre class="brush: js notranslate">try {
+ let result = syncDoSomething();
+ let newResult = syncDoSomethingElse(result);
+ let finalResult = syncDoThirdThing(newResult);
+ console.log(`Got the final result: ${finalResult}`);
+} catch(error) {
+ failureCallback(error);
+}
+</pre>
+
+<p>在 ECMAScript 2017 标准的 <code><a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Statements/async_function">async/await</a></code> 语法糖中,这种异步代码的对称性得到了极致的体现:</p>
+
+<pre class="brush: js notranslate">async function foo() {
+ try {
+ const result = await doSomething();
+ const newResult = await doSomethingElse(result);
+ const finalResult = await doThirdThing(newResult);
+ console.log(`Got the final result: ${finalResult}`);
+ } catch(error) {
+ failureCallback(error);
+ }
+}</pre>
+
+<p>这个例子是在 Promise 的基础上构建的,例如,<code>doSomething()</code> 与之前的函数是相同的。你可以在<a href="https://developers.google.com/web/fundamentals/getting-started/primers/async-functions">这里</a>阅读更多的与此语法相关的文章。</p>
+
+<p>通过捕获所有的错误,甚至抛出异常和程序错误,Promise 解决了回调地狱的基本缺陷。这对于构建异步操作的基础功能而言是很有必要的。</p>
+
+<h2 id="Promise_拒绝事件">Promise 拒绝事件</h2>
+
+<p>当 Promise 被拒绝时,会有下文所述的两个事件之一被派发到全局作用域(通常而言,就是{{domxref("window")}};如果是在 web worker 中使用的话,就是 {{domxref("Worker")}} 或者其他 worker-based 接口)。这两个事件如下所示:</p>
+
+<dl>
+ <dt>{{domxref("Window.rejectionhandled_event", "rejectionhandled")}}</dt>
+ <dd>当 Promise 被拒绝、并且在 <code>reject</code> 函数处理该 rejection 之后会派发此事件。</dd>
+ <dt>{{domxref("Window.unhandledrejection_event", "unhandledrejection")}}</dt>
+ <dd>当 Promise 被拒绝,但没有提供 <code>reject</code> 函数来处理该 rejection 时,会派发此事件。</dd>
+</dl>
+
+<p>以上两种情况中,{{domxref("PromiseRejectionEvent")}} 事件都有两个属性,一个是 {{domxref("PromiseRejectionEvent.promise", "promise")}} 属性,该属性指向被驳回的 Promise,另一个是 {{domxref("PromiseRejectionEvent.reason", "reason")}} 属性,该属性用来说明 Promise 被驳回的原因。</p>
+
+<p>因此,我们可以通过以上事件为 Promise 失败时提供补偿处理,也有利于调试 Promise 相关的问题。在每一个上下文中,该处理都是全局的,因此不管源码如何,所有的错误都会在同一个处理函数中被捕捉并处理。</p>
+
+<p>一个特别有用的例子:当你使用 {{Glossary("Node.js")}} 时,有些依赖模块可能会有未被处理的 rejected promises,这些都会在运行时打印到控制台。你可以在自己的代码中捕捉这些信息,然后添加与 {{domxref("Window.unhandledrejection_event", "unhandledrejection")}} 相应的处理函数来做分析和处理,或只是为了让你的输出更整洁。举例如下:</p>
+
+<pre class="brush: js notranslate">window.addEventListener("unhandledrejection", event =&gt; {
+ /* 你可以在这里添加一些代码,以便检查
+ event.promise 中的 promise 和
+ event.reason 中的 rejection 原因 */
+
+ event.preventDefault();
+}, false);
+</pre>
+
+<p>调用 event 的 {{domxref("Event.preventDefault", "preventDefault()")}} 方法是为了告诉 JavaScript 引擎当 Promise 被拒绝时不要执行默认操作,默认操作一般会包含把错误打印到控制台,Node 就是如此的。</p>
+
+<p>理想情况下,在忽略这些事件之前,我们应该检查所有被拒绝的 Promise,来确认这不是代码中的 bug。</p>
+
+<h2 id="在旧式回调_API_中创建_Promise">在旧式回调 API 中创建 Promise</h2>
+
+<p>可以通过 Promise 的构造器从零开始创建 {{jsxref("Promise")}}。 这种方式(通过构造器的方式)应当只在封装旧 API 的时候用到。</p>
+
+<p>理想状态下,所有的异步函数都已经返回 Promise 了。但有一些 API 仍然使用旧方式来传入的成功(或者失败)的回调。典型的例子就是 {{domxref("WindowTimers.setTimeout", "setTimeout()")}} 函数:</p>
+
+<pre class="brush: js notranslate">setTimeout(() =&gt; saySomething("10 seconds passed"), 10000);
+</pre>
+
+<p>混用旧式回调和 Promise 可能会造成运行时序问题。如果 <code>saySomething</code> 函数失败了,或者包含了编程错误,那就没有办法捕获它了。这得怪 <code>setTimeout</code>。</p>
+
+<p>幸运地是,我们可以用 Promise 来封装它。最好的做法是,将这些有问题的函数封装起来,留在底层,并且永远不要再直接调用它们:</p>
+
+<pre class="brush: js notranslate">const wait = ms =&gt; new Promise(resolve =&gt; setTimeout(resolve, ms));
+
+wait(10000).then(() =&gt; saySomething("10 seconds")).catch(failureCallback);
+</pre>
+
+<p>通常,Promise 的构造器接收一个执行函数(executor),我们可以在这个执行函数里手动地 resolve 和 reject 一个 Promise。既然 <code>setTimeout</code> 并不会真的执行失败,那么我们可以在这种情况下忽略 reject。</p>
+
+<h2 id="组合">组合</h2>
+
+<p>{{jsxref("Promise.resolve()")}} 和 {{jsxref("Promise.reject()")}} 是手动创建一个已经 resolve 或者 reject 的 Promise 快捷方法。它们有时很有用。</p>
+
+<p>{{jsxref("Promise.all()")}} 和 {{jsxref("Promise.race()")}} 是并行运行异步操作的两个组合式工具。</p>
+
+<p>我们可以发起并行操作,然后等多个操作全部结束后进行下一步操作,如下:</p>
+
+<pre class="brush: js notranslate">Promise.all([func1(), func2(), func3()])
+.then(([result1, result2, result3]) =&gt; { /* use result1, result2 and result3 */ });</pre>
+
+<p>可以使用一些聪明的 JavaScript 写法实现时序组合:</p>
+
+<pre class="brush: js notranslate">[func1, func2, func3].reduce((p, f) =&gt; p.then(f), Promise.resolve())
+.then(result3 =&gt; { /* use result3 */ });</pre>
+
+<p>通常,我们递归调用一个由异步函数组成的数组时,相当于一个 Promise 链:</p>
+
+<pre class="notranslate"><code>Promise.resolve().then(func1).then(func2).then(func3);</code></pre>
+
+<p>我们也可以写成可复用的函数形式,这在函数式编程中极为普遍:</p>
+
+<pre class="brush: js notranslate">const applyAsync = (acc,val) =&gt; acc.then(val);
+const composeAsync = (...funcs) =&gt; x =&gt; funcs.reduce(applyAsync, Promise.resolve(x));
+</pre>
+
+<p><code>composeAsync()</code> 函数将会接受任意数量的函数作为其参数,并返回一个新的函数,该函数接受一个通过 composition pipeline 传入的初始值。这对我们来说非常有益,因为任一函数可以是异步或同步的,它们能被保证按顺序执行:</p>
+
+<pre class="brush: js notranslate">const transformData = composeAsync(func1, func2, func3);
+const result3 = transformData(data);
+</pre>
+
+<p>在 ECMAScript 2017 标准中, 时序组合可以通过使用 <code>async/await</code> 而变得更简单:</p>
+
+<pre class="brush: js notranslate">let result;
+for (const f of [func1, func2, func3]) {
+ result = await f(result);
+}
+/* use last result (i.e. result3) */</pre>
+
+<h2 id="时序">时序</h2>
+
+<p>为了避免意外,即使是一个已经变成 resolve 状态的 Promise,传递给 <code><a href="/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Promise/then">then()</a></code> 的函数也总是会被异步调用:</p>
+
+<pre class="brush: js notranslate">Promise.resolve().then(() =&gt; console.log(2));
+console.log(1); // 1, 2
+</pre>
+
+<p>传递到 <code>then()</code> 中的函数被置入到一个微任务队列中,而不是立即执行,这意味着它是在 JavaScript 事件队列的所有运行时结束了,且事件队列被清空之后,才开始执行:</p>
+
+<pre class="brush: js notranslate">const wait = ms =&gt; new Promise(resolve =&gt; setTimeout(resolve, ms));
+
+wait().then(() =&gt; console.log(4));
+Promise.resolve().then(() =&gt; console.log(2)).then(() =&gt; console.log(3));
+console.log(1); // 1, 2, 3, 4</pre>
+
+<h2 id="嵌套">嵌套</h2>
+
+<p>简便的 Promise 链式编程最好保持扁平化,不要嵌套 Promise,因为嵌套经常会是粗心导致的。可查阅下一节的<a href="#常见错误">常见错误</a>中的例子。</p>
+
+<p>嵌套 Promise 是一种可以限制 <code>catch</code> 语句的作用域的控制结构写法。明确来说,嵌套的 <code>catch</code> 仅捕捉在其之前同时还必须是其作用域的 failureres,而捕捉不到在其链式以外或者其嵌套域以外的 error。如果使用正确,那么可以实现高精度的错误修复。</p>
+
+<pre class="brush: js notranslate">doSomethingCritical()
+.then(result =&gt; doSomethingOptional()
+ .then(optionalResult =&gt; doSomethingExtraNice(optionalResult))
+ .catch(e =&gt; {console.log(e.message)})) // 即使有异常也会忽略,继续运行;(最后会输出)
+.then(() =&gt; moreCriticalStuff())
+.catch(e =&gt; console.log("Critical failure: " + e.message));// 没有输出</pre>
+
+<p>注意,有些代码步骤是嵌套的,而不是一个简单的纯链式,这些语句前与后都被括号 <code>()</code> 包裹着。</p>
+
+<p>这个内部的 <code>catch</code>  语句仅能捕获到 <code>doSomethingOptional()</code> 和 <code>doSomethingExtraNice()</code> 的失败,<code>之后就恢复到moreCriticalStuff()</code> 的运行。重要提醒:如果 <code>doSomethingCritical()</code> 失败,这个错误仅会被最后的(外部)<code>catch</code> 语句捕获到。</p>
+
+<h2 id="常见错误">常见错误</h2>
+
+<p>在编写 Promise 链时,需要注意以下示例中展示的几个错误:</p>
+
+<pre class="brush: js example-bad notranslate">// 错误示例,包含 3 个问题!
+
+doSomething().then(function(result) {
+ doSomethingElse(result) // 没有返回 Promise 以及没有必要的嵌套 Promise
+ .then(newResult =&gt; doThirdThing(newResult));
+}).then(() =&gt; doFourthThing());
+// 最后,是没有使用 catch 终止 Promise 调用链,可能导致没有捕获的异常</pre>
+
+<p>第一个错误是没有正确地将事物相连接。当我们创建新 Promise 但忘记返回它时,会发生这种情况。因此,链条被打破,或者更确切地说,我们有两个独立的链条竞争(同时在执行两个异步而非一个一个的执行)。这意味着 <code>doFourthThing()</code> 不会等待 <code>doSomethingElse()</code> 或 <code>doThirdThing()</code> 完成,并且将与它们并行运行,可能是无意的。单独的链也有单独的错误处理,导致未捕获的错误。</p>
+
+<p>第二个错误是不必要地嵌套,实现第一个错误。嵌套还限制了内部错误处理程序的范围,如果是非预期的,可能会导致未捕获的错误。其中一个变体是 <a href="https://stackoverflow.com/questions/23803743/what-is-the-explicit-promise-construction-antipattern-and-how-do-i-avoid-it">Promise 构造函数反模式</a>,它结合了 Promise 构造函数的多余使用和嵌套。</p>
+
+<p>第三个错误是忘记用 <code>catch</code> 终止链。这导致在大多数浏览器中不能终止的 Promise 链里的 rejection。</p>
+
+<p>一个好的经验法则是总是返回或终止 Promise 链,并且一旦你得到一个新的 Promise,返回它。下面是修改后的平面化的代码:</p>
+
+<pre class="brush: js example-good notranslate">doSomething()
+.then(function(result) {
+ return doSomethingElse(result);
+})
+.then(newResult =&gt; doThirdThing(newResult))
+.then(() =&gt; doFourthThing())
+.catch(error =&gt; console.log(error));</pre>
+
+<p>注意:<code>() =&gt; x</code> 是 <code>() =&gt; { return x; }</code> 的简写。</p>
+
+<p>上述代码的写法就是具有适当错误处理的简单明确的链式写法。</p>
+
+<p>使用 <a href="/zh-CN/docs/Web/JavaScript/Reference/Statements/async_function">async/await</a> 可以解决以上大多数错误,使用 <code>async/await</code> 时,最常见的语法错误就是忘记了 <code><a href="/zh-CN/docs/Web/JavaScript/Reference/Operators/await">await</a></code> 关键字。</p>
+
+<h2 id="参见">参见</h2>
+
+<ul>
+ <li>{{jsxref("Promise.then()")}}</li>
+ <li><a href="/en-US/docs/Web/JavaScript/Reference/Statements/async_function"><code>async</code>/<code>await</code></a></li>
+ <li><a href="https://promisesaplus.com/">Promises/A+ specification</a></li>
+ <li><a href="https://medium.com/@ramsunvtech/promises-of-promise-part-1-53f769245a53">Venkatraman.R - JS Promise (Part 1, Basics)</a></li>
+ <li><a href="https://medium.com/@ramsunvtech/js-promise-part-2-q-js-when-js-and-rsvp-js-af596232525c">Venkatraman.R - JS Promise (Part 2 - Using Q.js, When.js and RSVP.js)</a></li>
+ <li><a href="https://tech.io/playgrounds/11107/tools-for-promises-unittesting/introduction">Venkatraman.R - Tools for Promises Unit Testing</a></li>
+ <li><a href="http://pouchdb.com/2015/05/18/we-have-a-problem-with-promises.html">Nolan Lawson: We have a problem with promises — Common mistakes with promises</a></li>
+</ul>
+
+<p>{{PreviousNext("Web/JavaScript/Guide/Details_of_the_Object_Model", "Web/JavaScript/Guide/Iterators_and_Generators")}}</p>
diff --git a/files/zh-cn/web/javascript/guide/working_with_objects/index.html b/files/zh-cn/web/javascript/guide/working_with_objects/index.html
new file mode 100644
index 0000000000..eb65155228
--- /dev/null
+++ b/files/zh-cn/web/javascript/guide/working_with_objects/index.html
@@ -0,0 +1,522 @@
+---
+title: 使用对象
+slug: Web/JavaScript/Guide/Working_with_Objects
+tags:
+ - JavaScript
+ - 初学者
+ - 基本语法
+ - 教程
+ - 文档
+ - 比较对象
+translation_of: Web/JavaScript/Guide/Working_with_Objects
+---
+<div><a id="#%E5%AF%B9%E8%B1%A1%E5%92%8C%E5%B1%9E%E6%80%A7" name="#%E5%AF%B9%E8%B1%A1%E5%92%8C%E5%B1%9E%E6%80%A7"></a>{{jsSidebar("JavaScript Guide")}} {{PreviousNext("Web/JavaScript/Guide/Text_formatting", "Web/JavaScript/Guide/Details_of_the_Object_Model")}}</div>
+
+<p class="summary"><span style="line-height: 1.5;">JavaScript </span>的设计是<span style="line-height: 1.5;">一个</span>简单的基于对象的范式。<span style="line-height: 1.5;">一个对象就是一系列属性的集合,一个属性包含一个名和一个值。一个属性的值可以是函数,这种情况下属性也被称为</span><em>方法</em><span style="line-height: 1.5;">。除了浏览器里面预定义的那些对象之外,你也可以定义你自己的对象。本章节讲述了怎么使用对象、属性、函数和方法,怎样实现自定义对象。</span></p>
+
+<h2 id="对象概述">对象概述</h2>
+
+<p><span style="line-height: 1.5;">javascript 中的对象(物体),和其它编程语言中的对象一样,可以比照现实生活中的对象(物体)来理解它。 javascript 中对象(物体)的概念可以比照着现实生活中实实在在的物体来理解。</span></p>
+
+<p>在javascript中,一个对象可以是一个单独的拥有属性和类型的实体。我们拿它和一个杯子做下类比。一个杯子是一个对象(物体),拥有属性。杯子有颜色,图案,重量,由什么材质构成等等。同样,javascript对象也有属性来定义它的特征。</p>
+
+<h2 id="对象和属性">对象和属性</h2>
+
+<p><span style="line-height: 1.5;">一个 javascript 对象有很多属性。一个对象的属性可以被解释成一个附加到对象上的变量。对象的属性和普通的 javascript 变量基本没什么区别,仅仅是属性属于某个对象。属性定义了对象的特征(译注:动态语言面向对象的鸭子类型)。你可以通过点符号来访问一个对象的属性。</span></p>
+
+<div style="margin-right: 270px;">
+<pre class="brush: js">objectName.propertyName
+</pre>
+</div>
+
+<p><span style="line-height: 1.5;">和其他 javascript 变量一样,对象的名字(可以是普通的变量)和属性的名字都是大小写敏感的。你可以在定义一个属性的时候就给它赋值。例如,我们创建一个myCar的对象然后给他三个属性,make,model,year。具体如下所示:</span></p>
+
+<pre class="brush: js">var myCar = new Object();
+myCar.make = "Ford";
+myCar.model = "Mustang";
+myCar.year = 1969; </pre>
+
+<p>对象中未赋值的属性的值为{{jsxref("undefined")}}(而不是{{jsxref("null")}})。</p>
+
+<pre class="brush: js">myCar.noProperty; // undefined
+</pre>
+
+<p>JavaScript 对象的属性也可以通过方括号访问或者设置(更多信息查看 <a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/Property_Accessors">property accessors</a>). 对象有时也被叫作关联数组, 因为每个属性都有一个用于访问它的字符串值。例如,你可以按如下方式访问 <code>myCar </code>对象的属性:</p>
+
+<pre class="brush: js">myCar["make"] = "Ford";
+myCar["model"] = "Mustang";
+myCar["year"] = 1969;
+</pre>
+
+<p>一个对象的属性名可以是任何有效的 JavaScript 字符串,或者可以被转换为字符串的任何类型,包括空字符串。然而,一个属性的名称如果不是一个有效的 JavaScript 标识符(例如,一个由空格或连字符,或者以数字开头的属性名),就只能通过方括号标记访问。这个标记法在属性名称是动态判定(属性名只有到运行时才能判定)时非常有用。例如:</p>
+
+<pre><code>// 同时创建四个变量,用逗号分隔
+</code>var myObj = new Object(),
+ str = "myString",
+ rand = Math.random(),
+ obj = new Object();
+
+myObj.type = "Dot syntax";
+myObj["date created"] = "String with space";
+myObj[str] = "String value";
+myObj[rand] = "Random Number";
+myObj[obj] = "Object";
+myObj[""] = "Even an empty string";
+
+console.log(myObj);
+</pre>
+
+<p><span id="result_box" lang="zh-CN"><span>请注意,方括号中的所有键都将转换为字符串类型,因为JavaScript中的对象只能使用String类型作为键类型。</span> <span>例如,在上面的代码中,当将键obj添加到myObj时,JavaScript将调用obj.toString()方法,并将此结果字符串用作新键。</span></span></p>
+
+<p>你也可以通过存储在变量中的字符串来访问属性:</p>
+
+<div style="width: auto;">
+<pre class="brush: js">var propertyName = "make";
+myCar[propertyName] = "Ford";
+
+propertyName = "model";
+myCar[propertyName] = "Mustang";
+</pre>
+</div>
+
+<p><span style="line-height: 1.5;">你可以在 </span><span style="line-height: 1.5;"> </span><a class="internal" href="/zh-CN/docs/JavaScript/Guide/Statements#for...in_Statement" style="line-height: 1.5;" title="zh-CN/docs/JavaScript/Guide/Statements#for...in Statement">for...in</a><span style="line-height: 1.5;"> 语句中使用方括号标记以枚举一个对象的所有属性。为了展示它如何工作,下面的函数当你将对象及其名称作为参数传入时,显示对象的属性:</span></p>
+
+<pre class="brush: js">function showProps(obj, objName) {
+ var result = "";
+ for (var i in obj) {
+ if (obj.hasOwnProperty(i)) {
+ result += objName + "." + i + " = " + obj[i] + "\n";
+ }
+ }
+ return result;
+}
+</pre>
+
+<p>因而,对于函数调用 <code>showProps(myCar, "myCar")</code> 将返回以下值:</p>
+
+<pre class="brush: js">myCar.make = Ford
+myCar.model = Mustang
+myCar.year = 1969
+</pre>
+
+<h2 id="枚举一个对象的所有属性">枚举一个对象的所有属性</h2>
+
+<p>从 <a href="/zh-CN/docs/JavaScript/ECMAScript_5_support_in_Mozilla" title="zh-CN/docs/JavaScript/ECMAScript 5 support in Mozilla">ECMAScript 5</a> 开始,有三种原生的方法用于列出或枚举对象的属性:</p>
+
+<ul>
+ <li><a href="/zh-CN/docs/JavaScript/Reference/Statements/for...in" title="zh-CN/docs/JavaScript/Reference/Statements/for...in">for...in</a> 循环<br>
+ 该方法依次访问一个对象及其原型链中所有可枚举的属性。</li>
+ <li><a href="/zh-CN/docs/JavaScript/Reference/Global_Objects/Object/keys" title="zh-CN/docs/JavaScript/Reference/Global Objects/Object/keys">Object.keys(o)</a><br>
+ 该方法返回对象 <code>o</code> 自身包含(不包括原型中)的所有可枚举属性的名称的数组。</li>
+ <li><a href="/zh-CN/docs/JavaScript/Reference/Global_Objects/Object/getOwnPropertyNames" title="zh-CN/docs/JavaScript/Reference/Global Objects/Object/getOwnPropertyNames">Object.getOwnPropertyNames(o)</a><br>
+ 该方法返回对象 <code>o</code> 自身包含(不包括原型中)的所有属性(无论是否可枚举)的名称的数组。</li>
+</ul>
+
+<p>在 ECMAScript 5 之前,没有原生的方法枚举一个对象的所有属性。然而,可以通过以下函数完成:</p>
+
+<pre class="brush: js">function listAllProperties(o){
+ var objectToInspect;
+ var result = [];
+
+ for(objectToInspect = o; objectToInspect !== null; objectToInspect = Object.getPrototypeOf(objectToInspect)){
+ result = result.concat(Object.getOwnPropertyNames(objectToInspect));
+ }
+
+ return result;
+}
+</pre>
+
+<p>这在展示 “隐藏”(在原型中的不能通过对象访问的属性,因为另一个同名的属性存在于原型链的早期)的属性时很有用。如果只想列出可访问的属性,那么只需要去除数组中的重复元素即可。</p>
+
+<h2 id="创建新对象">创建新对象</h2>
+
+<p>JavaScript 拥有一系列预定义的对象。另外,你可以创建你自己的对象。从  JavaScript 1.2 之后,你可以通过对象初始化器(Object Initializer)创建对象。或者你可以创建一个构造函数并使用该函数和 <code>new</code> 操作符初始化对象。</p>
+
+<h3 id="使用对象初始化器">使用对象初始化器</h3>
+
+<p>除了通过构造函数创建对象之外,你也可以通过对象初始化器创建对象。使用对象初始化器也被称作通过字面值创建对象。对象初始化器与 C++ 术语相一致。</p>
+
+<p>通过对象初始化器创建对象的语法如下:</p>
+
+<pre class="brush: js">var obj = { property_1: value_1, // property_# 可以是一个标识符...
+ 2: value_2, // 或一个数字...
+ <span lang="EN-US">["property" +3]</span>:<span lang="EN-US"> value_3</span>,<span lang="EN-US"><span>  </span></span>// 或<span>一个可计算的<span lang="EN-US">key</span>名<span lang="EN-US">...</span></span>
+ // ...,
+ "property n": value_n }; // 或一个字符串
+</pre>
+
+
+
+<p>这里 <code>obj</code> 是新对象的名称,每一个 <code>property_<em>i</em></code> 是一个标识符(可以是一个名称、数字或字符串字面量),并且每个 <code>value_<em>i</em></code> 是一个其值将被赋予 <span style="font-family: courier new,andale mono,monospace; line-height: 1.5;">property_</span><em>i </em><span style="line-height: 1.5;">的表达式。</span><code style="font-style: normal; line-height: 1.5;">obj</code><span style="line-height: 1.5;"> 与赋值是可选的;如果你不需要在其他地方引用对象,你就不需要将它赋给一个变量。(注意在接受一条语句的地方,你可能需要将对象字面量括在括号里,从而避免将字面量与块语句相混淆)</span></p>
+
+<p>如果一个对象是通过在顶级脚本的对象初始化器创建的,则 JavaScript 在每次遇到包含该对象字面量的表达式时都会创建对象。同样的,在函数中的初始化器在每次函数调用时也会被创建。</p>
+
+<p>下面的语句只有当 <code>cond</code> 表达式的值为 <code>true</code> 时创建对象并将其赋给变量 <code>x</code>。</p>
+
+<pre class="brush: js">if (cond) var x = {hi: "there"};
+</pre>
+
+<p>下例创建了有三个属性的 <code>myHonda</code> 对象。注意它的 <code>engine</code> 属性也是一个拥有自己属性的对象。</p>
+
+<pre class="brush: js">var myHonda = {color: "red", wheels: 4, engine: {cylinders: 4, size: 2.2}};
+</pre>
+
+<p>你也可以用对象初始化器来创建数组。参见 {{ web.link("Values%2C_variables%2C_and_literals#Array_literals", "array literals") }}.</p>
+
+<p>在 JavaScript 1.1 及更早版本中,你不能使用对象初始化器。你只能通过使用构造函数或其他对象的函数来创建对象。参见 {{ anch("使用构造函数") }}.</p>
+
+<h3 id="使用构造函数">使用构造函数</h3>
+
+<p>作为另一种方式,你可以通过两步来创建对象:</p>
+
+<ol>
+ <li>通过创建一个构造函数来定义对象的类型。首字母大写是非常普遍而且很恰当的惯用法。</li>
+ <li>通过 <code>new</code> 创建对象实例。</li>
+</ol>
+
+<p>为了定义对象类型,为对象类型创建一个函数以声明类型的名称、属性和方法。例如,你想为汽车创建一个类型,并且将这类对象称为 <code>car</code> ,并且拥有属性 make, model, 和 year,你可以创建如下的函数:</p>
+
+<pre class="brush: js">function Car(make, model, year) {
+ this.make = make;
+ this.model = model;
+ this.year = year;
+}
+</pre>
+
+<p>注意通过使用 this 将传入函数的值赋给对象的属性。</p>
+
+<p>现在你可以象这样创建一个 <code>mycar</code> 对象:</p>
+
+<pre class="brush: js">var mycar = new Car("Eagle", "Talon TSi", 1993);
+</pre>
+
+<p>该创建了 <code>mycar</code> 并且将指定的值赋给它的属性。因而 <code>mycar.make</code> 的值是字符串 "Eagle", <code>mycar.year</code> 的值是整数 1993,依此类推。</p>
+
+<p>你可以通过调用 <code>new</code> 创建任意数量的 <code>car</code> 对象。例如:</p>
+
+<pre class="brush: js">var kenscar = new Car("Nissan", "300ZX", 1992);
+var vpgscar = new Car("Mazda", "Miata", 1990);
+</pre>
+
+<p>一个对象的属性值可以是另一个对象。例如,假设你按如下方式定义了 <code>person</code> 对象:</p>
+
+<pre class="brush: js">function Person(name, age, sex) {
+ this.name = name;
+ this.age = age;
+ this.sex = sex;
+}
+</pre>
+
+<p>然后按如下方式创建了两个 <code>person</code> 实例:</p>
+
+<pre class="brush: js">var rand = new Person("Rand McKinnon", 33, "M");
+var ken = new Person("Ken Jones", 39, "M");
+</pre>
+
+<p>那么,你可以重写 <code>car</code> 的定义以包含一个拥有它的 <code>owner</code> 属性,如:</p>
+
+<pre class="brush: js">function Car(make, model, year, owner) {
+ this.make = make;
+ this.model = model;
+ this.year = year;
+ this.owner = owner;
+}
+</pre>
+
+<p>你可以按如下方式创建新对象:</p>
+
+<pre class="brush: js">var car1 = new Car("Eagle", "Talon TSi", 1993, rand);
+var car2 = new Car("Nissan", "300ZX", 1992, ken);
+</pre>
+
+<p>注意在创建新对象时,上面的语句将 <code>rand</code> 和 <code>ken</code> 作为 <code>owner</code> 的参数值,而不是传入字符串字面量或整数值。接下来你如果想找出 car2 的拥有者的姓名,你可以访问如下属性:</p>
+
+<pre class="brush: js">car2.owner.name
+</pre>
+
+<p>注意你总是可以为之前定义的对象增加新的属性。例如,语句</p>
+
+<pre class="brush: js">car1.color = "black";
+</pre>
+
+<p>为 <code>car1</code> 增加了 <code>color</code> 属性,并将其值设为 "black." 然而,这并不影响其他的对象。想要为某个类型的所有对象增加新属性,你必须将属性加入到 <code>car </code>对象类型的定义中。</p>
+
+<h3 id="使用_Object.create_方法">使用 Object.create 方法</h3>
+
+<p>对象也可以用 {{jsxref("Object.create()")}} 方法创建。该方法非常有用,因为它允许你为创建的对象选择一个原型对象,而不用定义构造函数。</p>
+
+<pre class="brush: js">// Animal properties and method encapsulation
+var Animal = {
+ type: "Invertebrates", // 属性默认值
+ displayType : function() { // 用于显示type属性的方法
+ console.log(this.type);
+ }
+}
+
+// 创建一种新的动物——animal1
+var animal1 = Object.create(Animal);
+animal1.displayType(); // Output:Invertebrates
+
+// 创建一种新的动物——Fishes
+var fish = Object.create(Animal);
+fish.type = "Fishes";
+fish.displayType(); // Output:Fishes
+</pre>
+
+<p>该函数更多的信息及详细用法,参见 {{ web.link("/zh-CN/docs/JavaScript/Reference/Global_Objects/Object/create", "Object.create method") }}</p>
+
+<h3 id="继承"><strong>继承</strong></h3>
+
+<p>所有的 JavaScript 对象至少继承于一个对象。被继承的对象被称作原型,并且继承的属性可通过构造函数的 <code>prototype</code> 对象找到。查看更多详细 <a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Inheritance_and_the_prototype_chain">Inheritance and the prototype chain</a></p>
+
+<h3 id="对象属性索引"><strong>对象属性索引</strong></h3>
+
+<p>在 JavaScript 1.0 中,你可以通过名称或序号访问一个属性。但是在 JavaScript 1.1 及之后版本中,如果你最初使用名称定义了一个属性,则你必须通过名称来访问它;而如果你最初使用序号来定义一个属性,则你必须通过索引来访问它。</p>
+
+<p>这个限制发生在你通过构造函数创建一个对象和它的属性(就象我们之前通过 <code>Car</code> 对象类型所做的那样)并且显式地定义了单独的属性(如 <code>m</code><span style="font-family: courier new,andale mono,monospace; line-height: 1.5;">yCar.color = "red")</span><span style="line-height: 1.5;">之时。如果你最初使用索引定义了一个对象属性,例如 <code>myCar[5] = "25"</code>,则你只可能通过 <code>myCar[5]</code> 引用它。</span></p>
+
+<p><span style="line-height: 1.5;">这条规则的例外是从与HTML对应的对象,例如 <code>forms</code> 数组。对于这些数组的元素,你总是既可以通过其序号(依据其在文档中出现的顺序),也可以按照其名称(如果有的话)访问它。举例而言,如果文档中的第二个 <code>&lt;form&gt;</code> 标签有一个 <code>NAME</code> 属性且值为<code> "myForm",访问该 form 的方式可以是 document.forms[1],document.forms["myForm"]或 document.myForm。</code></span></p>
+
+<p><span style="font-size: 1.7142857142857142rem; letter-spacing: -0.5px; line-height: 24px;">为对象类型定义属性</span></p>
+
+<p>你可以通过 <code>prototype </code>属性为之前定义的对象类型增加属性。这为该类型的所有对象,而不是仅仅一个对象增加了一个属性。下面的代码为所有类型为 <code>car </code>的对象增加了 <code>color</code> 属性,然后为对象 <code>car1</code> 的 <code>color</code> 属性赋值:</p>
+
+<pre class="brush: js">Car.prototype.color = null;
+car1.color = "black";
+</pre>
+
+<p>参见<span style="line-height: 1.5;"> </span><a href="/zh-CN/docs/JavaScript/Reference" style="line-height: 1.5; text-decoration: underline;" title="zh-CN/docs/JavaScript/Reference">JavaScript Reference</a><span style="line-height: 1.5;"> 中</span><span style="line-height: 1.5;"> Function 对象的 </span><a href="/zh-CN/docs/JavaScript/Reference/Global_Objects/Function/prototype" style="line-height: 1.5;" title="zh-CN/docs/JavaScript/Reference/Global Objects/Function/prototype"><code>prototype</code> 属性</a><span style="line-height: 1.5;"> 。</span></p>
+
+<h3 id="定义方法">定义方法</h3>
+
+<p>一个<em>方法</em> 是关联到某个对象的函数,或者简单地说,一个方法是一个值为某个函数的对象属性。定义方法就像定义普通的函数,除了它们必须被赋给对象的某个属性。查看 <a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Functions/Method_definitions">method definitions</a>了解更多详情例如:</p>
+
+<pre class="brush: js">objectName.methodname = function_name;
+
+var myObj = {
+ myMethod: function(params) {
+ // ...do something
+ }
+
+ // 或者 这样写也可以
+
+ myOtherMethod(params) {
+ // ...do something else
+ }
+};
+</pre>
+
+<p>这里 <code>objectName</code> 是一个已经存在的对象,<code>methodname</code> 是方法的名称,而 <code style="font-style: normal; line-height: 1.5;">function_name</code><span style="line-height: 1.5;"> </span><span style="line-height: 1.5;">是函数的名称。</span></p>
+
+<p>你可以在对象的上下文中象这样调用方法:</p>
+
+<pre class="brush: js">object.methodname(params);
+</pre>
+
+<p>你可以在对象的构造函数中包含方法定义来<span style="line-height: 1.5;">为某个对象类型定义方法。例如,你可以为之前定义的 <code>car</code> 对象定义一个函数格式化并显示其属性:</span></p>
+
+<pre class="brush: js">function displayCar() {
+ var result = `A Beautiful ${this.year} ${this.make} ${this.model}`;
+ pretty_print(result);
+}
+</pre>
+
+<p>这里 <code>pretty_print</code> 是一个显示横线和一个字符串的函数。注意使用 this 指代方法所属的对象。</p>
+
+<p>你可以在对象定义中通过增加下述语句将这个函数变成 <code>Car</code> 的方法:</p>
+
+<pre class="brush: js">this.displayCar = displayCar;
+</pre>
+
+<p>因此,<code>Car</code> 的完整定义看上去将是:</p>
+
+<pre class="brush: js">function Car(make, model, year, owner) {
+ this.make = make;
+ this.model = model;
+ this.year = year;
+ this.owner = owner;
+ this.displayCar = displayCar;
+}
+</pre>
+
+<p>然后你可以按如下方式为每个对象调用 <code>displayCar</code> 方法:</p>
+
+<pre class="brush: js">car1.displayCar();
+car2.displayCar();
+</pre>
+
+
+
+<h3 id="通过_this_引用对象">通过 <code>this</code> 引用对象</h3>
+
+
+
+<p>JavaScript 有一个特殊的关键字 <code>this</code>,它可以在方法中使用以指代当前对象。例如,假设你有一个名为 <code>validate</code> 的函数,它根据给出的最大与最小值检查某个对象的 <code>value</code> 属性:</p>
+
+<pre class="brush: js">function validate(obj, lowval, hival) {
+ if ((obj.value &lt; lowval) || (obj.value &gt; hival)) {
+ alert("Invalid Value!");
+ }
+}
+</pre>
+
+<p>然后,你可以在每个元素的 <code>onchange</code> 事件处理器中调用 <code>validate</code>,并通过 <code>this</code> 传入相应元素,代码如下:</p>
+
+<pre class="brush: html">&lt;input type="text" name="age" size="3"
+ onChange="validate(this, 18, 99)"&gt;
+</pre>
+
+<p>总的说来, <code>this</code> 在一个方法中指调用的对象。</p>
+
+<p>当与 <code>form</code> 属性一起使用时,<code>this </code>可以指代当前对象的父窗体。在下面的例子中,窗体 <code>myForm</code> 包含一个 <code>Text </code>对象和一个按钮,当用户点击按键,<code>Text</code> 对象的值被设为窗体的名称。按钮的 <code>onclick</code> 事件处理器使用 <code>this.form</code> 以指代其父窗体,即 <code>myForm</code>。</p>
+
+<pre class="brush: html">&lt;form name="myForm"&gt;
+&lt;p&gt;&lt;label&gt;Form name:&lt;input type="text" name="text1" value="Beluga"&gt;&lt;/label&gt;
+&lt;p&gt;&lt;input name="button1" type="button" value="Show Form Name"
+ onclick="this.form.text1.value = this.form.name"&gt;
+&lt;/p&gt;
+&lt;/form&gt;</pre>
+
+<h3 id="定义_getters_与_setters"><strong>定义 getters 与 setters</strong></h3>
+
+<p>一个 <a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Functions/get">getter</a> 是一个获取某个特定属性的值的方法。一个  <a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Functions/set">setter</a> 是一个设定某个属性的值的方法。你可以为预定义的或用户定义的对象定义 getter 和 setter 以支持新增的属性。定义 getter 和 setter 的语法采用对象字面量语法。</p>
+
+<p>下面例子描述了getters 和 setters 是如何为用户定义的对象<code> o</code> 工作的。</p>
+
+<pre class="brush: js">var o = {
+ a: 7,
+ get b() {
+ return this.a + 1;
+ },
+ set c(x) {
+ this.a = x / 2
+ }
+};
+
+console.log(o.a); // 7
+console.log(o.b); // 8
+o.c = 50;
+console.log(o.a); // 25</pre>
+
+<p><code>o</code> 对象的属性如下:</p>
+
+<ul>
+ <li><code>o.a</code> — 数字</li>
+ <li><code>o.b</code> — 返回 <code>o.a</code> + 1 的 getter</li>
+ <li><code>o.c</code> — 由  <code>o.c 的值所设置 <code>o.a</code> 值的</code> setter</li>
+</ul>
+
+<p>请注意在一个对象字面量语法中定义getter和setter使用"[gs]et property()"的方式(相比较于__define[GS]etter__)时,并不是获取和设置某个属性自身,容易让人误以为是"[gs]et propertyName(){ }"这样错误的使用方法。定义一个getter或setter函数使用语法"[gs]et property()",定义一个已经声明的函数作为的getter和setter方法,使用<code><a href="/zh-CN/docs/JavaScript/Reference/Global_Objects/Object/defineProperty" title="zh-CN/docs/Core JavaScript 1.5 Reference/Global
+Objects/Object/defineProperty">Object.defineProperty</a></code>(或者 <code><a href="/zh-CN/docs/JavaScript/Reference/Global_Objects/Object/defineGetter" title="zh-CN/docs/Core JavaScript 1.5 Reference/Global
+Objects/Object/defineGetter">Object.prototype.__defineGetter__</a></code> 旧语法回退)</p>
+
+<p>下面这个例子展示使用getter和setter方法扩展 {{jsxref("Date")}}原型,为预定义好的Date类添加一个year的属性。定义属性year的getter和setter方法用到了Date类中已存在的getFullYear和setFullYear方法。</p>
+
+<p>定义属性year的getter和setter:</p>
+
+<pre class="brush: js">var d = Date.prototype;
+Object.defineProperty(d, "year", {
+  get: function() { return this.getFullYear() },
+  set: function(y) { this.setFullYear(y) }
+});
+</pre>
+
+<p>通过一个Date对象使用getter和setter:</p>
+
+<pre class="brush: js">var now = new Date();
+console.log(now.year); // 2000
+now.year = 2001; // 987617605170
+console.log(now);
+// Wed Apr 18 11:13:25 GMT-0700 (Pacific Daylight Time) 2001
+</pre>
+
+<p>原则上,getter 和 setter 既可以:</p>
+
+<ul>
+ <li>使用 <a href="#使用对象初始化器">使用对象初始化器</a> 定义</li>
+ <li>也可以之后随时使用 getter 和 setter 添加方法添加到任何对象</li>
+</ul>
+
+<p>当使用 <a href="#使用对象初始化器">使用对象初始化器</a> 的方式定义getter和setter时,只需要在getter方法前加get,在setter方法前加set,当然,getter方法必须是无参数的,setter方法只接受一个参数(设置为新值),例如:</p>
+
+<pre class="brush: js">var o = {
+ a: 7,
+ <strong>get</strong> b() { return this.a + 1; },
+ <strong>set</strong> c(x) { this.a = x / 2; }
+};
+</pre>
+
+<p>使用Object.defineProperties的方法,同样也可以对一个已创建的对象在任何时候为其添加getter或setter方法。这个方法的第一个参数是你想定义getter或setter方法的对象,第二个参数是一个对象,这个对象的属性名用作getter或setter的名字,属性名对应的属性值用作定义getter或setter方法的函数,下面是一个例子定义了和前面例子一样的getter和setter方法:</p>
+
+<pre class="brush: js">var o = { a:0 }
+
+Object.defineProperties(o, {
+ "b": { get: function () { return this.a + 1; } },
+ "c": { set: function (x) { this.a = x / 2; } }
+});
+
+o.c = 10 // Runs the setter, which assigns 10 / 2 (5) to the 'a' property
+console.log(o.b) // Runs the getter, which yields a + 1 or 6
+</pre>
+
+<p>这两种定义方式的选择取决于你的编程风格和手头的工作量。当你定义一个原型准备进行初始化时,可以选择第一种方式,这种方式更简洁和自然。但是,当你需要添加getter和setter方法 —— 因为并没有编写原型或者特定的对象 ——使用第二种方式更好。第二种方式可能更能表现JavaScript语法的动态特性——但也会使代码变得难以阅读和理解。</p>
+
+<h3 id="删除属性">删除属性</h3>
+
+<p>你可以用 <a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/delete">delete</a> 操作符删除一个<strong style="color: red;">不是继承而来</strong>的属性。下面的例子说明如何删除一个属性:</p>
+
+<pre class="brush: js">//Creates a new object, myobj, with two properties, a and b.
+var myobj = new Object;
+myobj.a = 5;
+myobj.b = 12;
+
+//Removes the a property, leaving myobj with only the b property.
+delete myobj.a;
+</pre>
+
+<p>如果一个全局变量不是用 <code>var</code> 关键字声明的话,你也可以用 <code>delete</code> 删除它:</p>
+
+<pre class="brush: js">g = 17;
+delete g;
+</pre>
+
+<p>参见<code>{{ web.link("Expressions_and_operators#delete", "delete") }}</code> 以获取更多信息。</p>
+
+<h3 id="比较对象">比较对象</h3>
+
+<p>在 JavaScript 中 objects 是一种引用类型。两个独立声明的对象永远也不会相等,即使他们有相同的属性,只有在比较一个对象和这个对象的引用时,才会返回true.</p>
+
+<pre class="brush: js">// 两个变量, 两个具有同样的属性、但不相同的对象
+var fruit = {name: "apple"};
+var fruitbear = {name: "apple"};
+
+fruit == fruitbear // return false
+fruit === fruitbear // return false
+</pre>
+
+<div class="note">
+<p><strong>注意:</strong> "===" 运算符用来检查数值是否相等: 1 === "1"返回false,而1 == "1" 返回true</p>
+</div>
+
+<pre class="brush: js">// 两个变量, 同一个对象
+var fruit = {name: "apple"};
+var fruitbear = fruit; // 将fruit的对象<strong>引用</strong>(reference)赋值给 fruitbear
+ // 也称为将fruitbear“<em><strong>指向</strong></em>”fruit对象
+// fruit与fruitbear都指向同样的对象
+fruit == fruitbear // return true
+fruit === fruitbear // return true</pre>
+
+<p><font face="Consolas, Liberation Mono, Courier, monospace">了解更多关于比较操作符的用法,查看</font> <a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/Comparison_Operators">Comparison operators</a>.</p>
+
+<h2 id="附加参考">附加参考</h2>
+
+<ul>
+ <li>想要深入了解,请阅读<a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Guide/Details_of_the_Object_Model">details of javaScript's objects model</a>。</li>
+ <li>想要学习 ECMAScript 2015中类(一种创建对象的新方式),请阅读 <a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Classes">JavaScript classes</a> 章节。</li>
+</ul>
+
+
+
+<p>{{PreviousNext("Web/JavaScript/Guide/Regular_Expressions", "Web/JavaScript/Guide/Details_of_the_Object_Model")}}</p>
+
+<div></div>