diff --git a/files/zh-cn/learn/javascript/asynchronous/index.md b/files/zh-cn/learn/javascript/asynchronous/index.md index 181c26514669fb..504bee2a07e74b 100644 --- a/files/zh-cn/learn/javascript/asynchronous/index.md +++ b/files/zh-cn/learn/javascript/asynchronous/index.md @@ -1,5 +1,5 @@ --- -title: 异步JavaScript +title: 异步 JavaScript slug: Learn/JavaScript/Asynchronous tags: - JavaScript @@ -30,7 +30,7 @@ original_slug: learn/JavaScript/异步 ## 预备知识 -异步 JavaScript 是一个相当高级的话题,建议你先完成 [JavaScript 第一步](/zh-CN/docs/Learn/JavaScript/First_steps)和[创建JavaScript代码块](/zh-CN/docs/Learn/JavaScript/Building_blocks) 两个模块的学习后再来学习。 +异步 JavaScript 是一个相当高级的话题,建议你先完成 [JavaScript 第一步](/zh-CN/docs/Learn/JavaScript/First_steps)和[创建 JavaScript 代码块](/zh-CN/docs/Learn/JavaScript/Building_blocks) 两个模块的学习后再来学习。 > **备注:** 如果你工作在一个无权创建自己文件的电脑/平板/其他设备上,你需要在一个在线编程工具上试验(大多数)代码示例,如 [JSBin](https://jsbin.com/) 或者 [Glitch](https://glitch.com). diff --git a/files/zh-cn/learn/javascript/asynchronous/introducing/index.md b/files/zh-cn/learn/javascript/asynchronous/introducing/index.md index 6f21025d8d54ed..d3b6c4d6548472 100644 --- a/files/zh-cn/learn/javascript/asynchronous/introducing/index.md +++ b/files/zh-cn/learn/javascript/asynchronous/introducing/index.md @@ -40,7 +40,7 @@ original_slug: learn/JavaScript/异步/简介 ## 同步编程 -观察下面的代码: +观察下面的代码: ```js const name = 'Miriam'; @@ -49,7 +49,7 @@ console.log(greeting); // "Hello, my name is Miriam!" ``` -这段代码: +这段代码: 1. 声明了一个叫做 `name` 的字符串常量 2. 声明了另一个叫做 `greeting` 的字符串常量(并使用了 `name` 常量的值) @@ -259,7 +259,7 @@ function doOperation() { doOperation(); ``` -现在我们有一个被分成三步的操作,每一步都依赖于上一步。在这个例子中,第一步给输入的数据加1,第二步加2,第三步加3。从输入0开始,最终结果是6(0+1+2+3)。作为同步代码,这很容易理解。但是如果我们用回调来实现这些步骤呢? +现在我们有一个被分成三步的操作,每一步都依赖于上一步。在这个例子中,第一步给输入的数据加 1,第二步加 2,第三步加 3。从输入 0 开始,最终结果是 6(0+1+2+3)。作为同步代码,这很容易理解。但是如果我们用回调来实现这些步骤呢? ```js function doStep1(init, callback) { diff --git a/files/zh-cn/learn/javascript/asynchronous/introducing_workers/index.md b/files/zh-cn/learn/javascript/asynchronous/introducing_workers/index.md index 65cf1b1c0bbc16..d257154ad257f7 100644 --- a/files/zh-cn/learn/javascript/asynchronous/introducing_workers/index.md +++ b/files/zh-cn/learn/javascript/asynchronous/introducing_workers/index.md @@ -143,7 +143,7 @@ textarea { // 在 "generate.js" 中创建一个新的 worker const worker = new Worker('./generate.js'); -// 当用户点击 "Generate primes" 时, 给 worker 发送一条消息。 +// 当用户点击 "Generate primes" 时,给 worker 发送一条消息。 // 消息中的 command 属性是 "generate", 还包含另外一个属性 "quota",即要生成的质数。 document.querySelector('#generate').addEventListener('click', () => { const quota = document.querySelector('#quota').value; @@ -216,7 +216,7 @@ worker 要做的第一件事情就是开始监听来自主脚本的消息。这 `generatePrimes()` 函数与同步版本类似,只不过我们在完成后向主脚本发送一条消息,而不是返回一个值。我们对此使用 {{DOMxRef("dedicatedWorkerGlobalScope.postMessage()", "postMessage()")}} 函数,就像在 worker 中 `addEventListener`是全局函数一样。如我们所见,主脚本正在监听这条消息并且将会在收到消息后更新 DOM。 -> **备注:** 要运行此站点,你必须运行一个本地 web 服务器,因为 file:// URLs 不允许加载 workers。参考我们的[设置一个本地测试服务器](/zh-CN/docs/Learn/Common_questions/set_up_a_local_testing_server)的指导。完成后,你应该可以点击 "Generate primes" 并且使你的主页面保持响应。 +> **备注:** 要运行此站点,你必须运行一个本地 web 服务器,因为 file:// URLs 不允许加载 workers。参考我们的 [设置一个本地测试服务器](/zh-CN/docs/Learn/Common_questions/set_up_a_local_testing_server) 的指导。完成后,你应该可以点击 "Generate primes" 并且使你的主页面保持响应。 > 如果你在创建和运行这个样例的过程中有疑问,你可以在 [https://github.com/mdn/learning-area/blob/main/javascript/asynchronous/workers/finished](https://github.com/mdn/learning-area/blob/main/javascript/asynchronous/workers/finished) 查看完成后的版本,并且在 [https://mdn.github.io/learning-area/javascript/asynchronous/workers/finished](https://mdn.github.io/learning-area/javascript/asynchronous/workers/finished) 进行在线尝试。 ## 其他类型的 worker @@ -232,7 +232,7 @@ worker 要做的第一件事情就是开始监听来自主脚本的消息。这 在本文中,我们介绍了 web workers,它使得 web 应用能够离线加载任务到单独的线程中。主线程和 worker 不直接共享任何变量,但是可以通过发送消息来进行通信,这些消息作为 `message` 事件被对方接受。 -Workers 尽管不能访问主应用程序能访问的所有 API,尤其是不能访问 DOM, 但是可以作为使主应用程序保持响应的一个有效的方式。 +Workers 尽管不能访问主应用程序能访问的所有 API,尤其是不能访问 DOM,但是可以作为使主应用程序保持响应的一个有效的方式。 ## 参见 diff --git a/files/zh-cn/learn/javascript/asynchronous/promises/index.html b/files/zh-cn/learn/javascript/asynchronous/promises/index.html index 345f0c20814987..14ce8c5706e1c2 100644 --- a/files/zh-cn/learn/javascript/asynchronous/promises/index.html +++ b/files/zh-cn/learn/javascript/asynchronous/promises/index.html @@ -8,24 +8,24 @@
{{PreviousMenuNext("Learn/JavaScript/Asynchronous/Timeouts_and_intervals", "Learn/JavaScript/Asynchronous/Async_await", "Learn/JavaScript/Asynchronous")}}
-

Promise 是 JavaScript 语言的一个相对较新的功能,允许你推迟进一步的操作,直到上一个操作完成或响应其失败。这对于设置一系列异步操作以正常工作非常有用。本文向你展示了promises如何工作,如何在Web API中使用它们以及如何编写自己的API

+

Promise 是 JavaScript 语言的一个相对较新的功能,允许你推迟进一步的操作,直到上一个操作完成或响应其失败。这对于设置一系列异步操作以正常工作非常有用。本文向你展示了 promises 如何工作,如何在 Web API 中使用它们以及如何编写自己的 API

- - + + - - + +
前提条件:基本的计算机素养,具备基础的JavaScript知识前提条件:基本的计算机素养,具备基础的 JavaScript 知识
目标:理解并使用学习如何使用Promises目标:理解并使用学习如何使用 Promises
-

什么是promises?

+

什么是 promises?

-

我们在教程的第一篇文章中简要地了解了 Promises,接下来我们将在更深层次理解Promise。

+

我们在教程的第一篇文章中简要地了解了 Promises,接下来我们将在更深层次理解 Promise。

本质上,Promise 是一个对象,代表操作的中间状态 —— 正如它的单词含义 '承诺' ,它保证在未来可能返回某种结果。虽然 Promise 并不保证操作在何时完成并返回结果,但是它保证当结果可用时,你的代码能正确处理结果,当结果不可用时,你的代码同样会被执行,来优雅的处理错误。

@@ -35,7 +35,7 @@

什么是promises?

该按钮的处理程序调用 {{domxref("MediaDevices.getUserMedia", "getUserMedia()")}} 来访问用户的摄像头和麦克风。由于 getUserMedia() 必须确保用户具有使用这些设备的权限,并询问用户要使用哪个麦克风和摄像头(或者是否仅进行语音通话,以及其他可能的选项),因此它会产生阻塞,直到用户做出所有的决定,并且摄像头和麦克风都已启用。此外,用户可能不会立即响应权限请求。所以 getUserMedia() 可能需要很长时间。

-

由于 getUserMedia() 是在浏览器的主线程进行调用,整个浏览器将会处于阻塞状态直到 getUserMedia() 返回,这是不应该发生的;不使用Promise,浏览器将处于不可用状态直到用户为摄像头和麦克风做出决定。因此 getUserMedia() 返回一个Promise对象,即 {{jsxref("promise")}},一旦  {{domxref("MediaStream")}} 流可用才去解析,而不是等待用户操作、启动选中的设备并直接返回从所选资源创建的 {{domxref("MediaStream")}} 流。

+

由于 getUserMedia() 是在浏览器的主线程进行调用,整个浏览器将会处于阻塞状态直到 getUserMedia() 返回,这是不应该发生的;不使用 Promise,浏览器将处于不可用状态直到用户为摄像头和麦克风做出决定。因此 getUserMedia() 返回一个 Promise 对象,即 {{jsxref("promise")}},一旦  {{domxref("MediaStream")}} 流可用才去解析,而不是等待用户操作、启动选中的设备并直接返回从所选资源创建的 {{domxref("MediaStream")}} 流。

上述视频聊天应用程序的代码可能像下面这样:

@@ -52,14 +52,14 @@

什么是promises?

} -

这个函数在开头调用 setStatusMessage() 来更新状态显示信息"Calling...", 表示正在尝试通话。接下来调用 getUserMedia(),请求具有视频及音频轨的流,一旦获得这个流,就将其显示在"selfViewElem"的video元素中。接下来将这个流的每个轨道添加到表示与另一个用户的连接的 WebRTC,参见{{domxref("RTCPeerConnection")}}。在这之后,状态显示为"Connected"。

+

这个函数在开头调用 setStatusMessage() 来更新状态显示信息"Calling...", 表示正在尝试通话。接下来调用 getUserMedia(),请求具有视频及音频轨的流,一旦获得这个流,就将其显示在"selfViewElem"的 video 元素中。接下来将这个流的每个轨道添加到表示与另一个用户的连接的 WebRTC,参见{{domxref("RTCPeerConnection")}}。在这之后,状态显示为"Connected"。

-

如果getUserMedia()失败,则catch块运行。这使用setStatusMessage()更新状态框以指示发生错误。

+

如果getUserMedia()失败,则 catch 块运行。这使用setStatusMessage()更新状态框以指示发生错误。

这里重要的是getUserMedia()调用几乎立即返回,即使尚未获得相机流。即使handleCallButton()函数向调用它的代码返回结果,当getUserMedia()完成工作时,它也会调用你提供的处理程序。只要应用程序不假设流式传输已经开始,它就可以继续运行。

-

注意:  如果你有兴趣,可以在文章Signaling and video calling中了解有关此高级主题的更多信息。在该示例中使用与此类似的代码,但更完整。

+

注意:  如果你有兴趣,可以在文章Signaling and video calling中了解有关此高级主题的更多信息。在该示例中使用与此类似的代码,但更完整。

 回调函数的麻烦

@@ -86,9 +86,9 @@

 回调函数的麻烦

这很麻烦且难以阅读(通常称为“回调地狱”),需要多次调用failureCallback()(每个嵌套函数一次),还有其他问题。

-

使用promise改良

+

使用 promise 改良

-

Promises使得上面的情况更容易编写,解析和运行。如果我们使用异步promises代表上面的伪代码,我们最终会得到这样的结果:

+

Promises 使得上面的情况更容易编写,解析和运行。如果我们使用异步 promises 代表上面的伪代码,我们最终会得到这样的结果:

chooseToppings()
 .then(function(toppings) {
@@ -102,7 +102,7 @@ 

使用promise改良

}) .catch(failureCallback);
-

这要好得多 - 更容易看到发生了什么,我们只需要一个.catch()块来处理所有错误,它不会阻塞主线程(所以我们可以在等待时继续玩视频游戏为了准备好收集披萨),并保证每个操作在运行之前等待先前的操作完成。我们能够以这种方式一个接一个地链接多个异步操作,因为每个.then()块返回一个新的promise,当.then()块运行完毕时它会解析。聪明,对吗?

+

这要好得多 - 更容易看到发生了什么,我们只需要一个.catch()块来处理所有错误,它不会阻塞主线程(所以我们可以在等待时继续玩视频游戏为了准备好收集披萨),并保证每个操作在运行之前等待先前的操作完成。我们能够以这种方式一个接一个地链接多个异步操作,因为每个.then()块返回一个新的 promise,当.then()块运行完毕时它会解析。聪明,对吗?

使用箭头函数,你可以进一步简化代码:

@@ -138,21 +138,21 @@

使用promise改良

注意: 你可以使用 async/await 语法进行进一步的改进,我们将在下一篇文章中深入讨论。

-

最基本的,promise与事件监听器类似,但有一些差异:

+

最基本的,promise 与事件监听器类似,但有一些差异:

-

 解释promise的基本语法:一个真实的例子

+

 解释 promise 的基本语法:一个真实的例子

-

Promises 很重要,因为大多数现代Web API都将它们用于执行潜在冗长任务的函数。要使用现代Web技术,你需要使用promises。在本章的后面我们将看看如何编写自己的promises,但是现在我们将看一些你将在Web API中遇到的简单示例。

+

Promises 很重要,因为大多数现代 Web API 都将它们用于执行潜在冗长任务的函数。要使用现代 Web 技术,你需要使用 promises。在本章的后面我们将看看如何编写自己的 promises,但是现在我们将看一些你将在 Web API 中遇到的简单示例。

-

在第一个示例中,我们将使用fetch()方法从Web获取图像,blob() 方法来转换获取响应的原始内容到 Blob 对象,然后在 <img> 元素内显示该blob。这与我们在 first article of the series中看到的示例非常相似,但是会在构建你自己的基于 promise 的代码时有所不同。 

+

在第一个示例中,我们将使用fetch()方法从 Web 获取图像,blob() 方法来转换获取响应的原始内容到 Blob 对象,然后在 <img> 元素内显示该blob。这与我们在 first article of the series中看到的示例非常相似,但是会在构建你自己的基于 promise 的代码时有所不同。 

-

注意: 下列代码无法直接运行(i.e. via a file:// URL)。你需要本地测试服务器,或是 GlitchGitHub pages 这样的在线解决方案。

+

注意:下列代码无法直接运行 (i.e. via a file:// URL)。你需要本地测试服务器,或是 GlitchGitHub pages 这样的在线解决方案。

    @@ -160,20 +160,20 @@

     解释promise的

    首先,下载我们的 simple HTML templatesample image file

  1. -

    将 {{htmlelement("script")}} 元素添加在HTML {{htmlelement("body")}} 的底部。

    +

    将 {{htmlelement("script")}} 元素添加在 HTML {{htmlelement("body")}} 的底部。

  2. 在 {{HTMLElement("script")}} 元素内,添加以下行:

    let promise = fetch('coffee.jpg');
    -

    这会调用 fetch() 方法,将图像的URL作为参数从网络中提取。这也可以将options对象作为可选的第二个参数,但我们现在只使用最简单的版本。我们将 fetch() 返回的promise对象存储在一个名为promise的变量中。正如我们之前所说的,这个对象代表了一个最初既不成功也不失败的中间状态 - 这个状态下的promise的官方术语叫作pending

    +

    这会调用 fetch() 方法,将图像的 URL 作为参数从网络中提取。这也可以将 options 对象作为可选的第二个参数,但我们现在只使用最简单的版本。我们将 fetch() 返回的 promise 对象存储在一个名为 promise 的变量中。正如我们之前所说的,这个对象代表了一个最初既不成功也不失败的中间状态 - 这个状态下的 promise 的官方术语叫作pending

  3. -
  4. 为了响应成功完成操作(在这种情况下,当返回{{domxref("Response")}}时),我们调用promise对象的.then()方法。 .then()块中的回调(称为执行程序)仅在promise调用成功完成时运行并返回{{domxref("Response")}}对象 - 在promise-speak中,当它已被满足时。它将返回的{{domxref("Response")}}对象作为参数传递。
  5. +
  6. 为了响应成功完成操作(在这种情况下,当返回{{domxref("Response")}}时),我们调用 promise 对象的。then()方法。 .then()块中的回调(称为执行程序)仅在 promise 调用成功完成时运行并返回{{domxref("Response")}}对象 - 在 promise-speak 中,当它已被满足时。它将返回的{{domxref("Response")}}对象作为参数传递。
-

注意: .then()块的工作方式类似于使用AddEventListener()向对象添加事件侦听器时的方式。它不会在事件发生之前运行(当promise履行时)。最显着的区别是.then()每次使用时只运行一次,而事件监听器可以多次调用。

+

注意: .then()块的工作方式类似于使用AddEventListener()向对象添加事件侦听器时的方式。它不会在事件发生之前运行(当 promise 履行时)。最显着的区别是.then()每次使用时只运行一次,而事件监听器可以多次调用。

我们立即对此响应运行blob()方法以确保响应主体完全下载,并且当它可用时将其转换为我们可以执行某些操作的Blob对象。返回的结果如下:

@@ -187,7 +187,7 @@

 解释promise的 } -

好的,我们还需要做点额外的工作。Fetch promises 不会产生 404 或 500错误,只有在产生像网路故障的情况时才会不工作。总的来说,Fetch promises 总是成功运行,即使response.ok 属性是 false。为了产生404错误,我们需要判断 response.ok ,如果是 false,抛出错误,否则返回 blob。就像下面的代码这样做。

+

好的,我们还需要做点额外的工作。Fetch promises 不会产生 404 或 500 错误,只有在产生像网路故障的情况时才会不工作。总的来说,Fetch promises 总是成功运行,即使response.ok 属性是 false。为了产生 404 错误,我们需要判断 response.ok ,如果是 false,抛出错误,否则返回 blob。就像下面的代码这样做。

let promise2 = promise.then(response => {
   if (!response.ok) {
@@ -197,7 +197,7 @@ 

 解释promise的 } });

-

5. 每次调用.then()都会创建一个新的promise。这非常有用;因为blob()方法也返回一个promise,我们可以通过调用第二个promise的.then()方法来处理它在履行时返回的Blob对象。因为我们想要对blob执行一些更复杂的操作,而不仅仅运行单个方法并返回结果,这次我们需要将函数体包装成花括号(否则会抛出错误)。

+

5. 每次调用.then()都会创建一个新的 promise。这非常有用;因为blob()方法也返回一个 promise,我们可以通过调用第二个 promise 的.then()方法来处理它在履行时返回的Blob对象。因为我们想要对blob执行一些更复杂的操作,而不仅仅运行单个方法并返回结果,这次我们需要将函数体包装成花括号(否则会抛出错误)。

将以下内容添加到代码的末尾:

@@ -210,25 +210,25 @@

 解释promise的 image.src = objectURL; document.body.appendChild(image); -

这里我们运行{{domxref("URL.createObjectURL()")}}方法,将其作为Blob在第二个promise实现时返回的参数传递。这将返回指向该对象的URL。然后我们创建一个{{htmlelement("img")}}元素,将其src属性设置为等于对象URL并将其附加到DOM,这样图像就会显示在页面上!

+

这里我们运行{{domxref("URL.createObjectURL()")}}方法,将其作为Blob在第二个 promise 实现时返回的参数传递。这将返回指向该对象的 URL。然后我们创建一个{{htmlelement("img")}}元素,将其src属性设置为等于对象 URL 并将其附加到 DOM,这样图像就会显示在页面上!

-

如果你保存刚刚创建的HTML文件并将其加载到浏览器中,你将看到图像按预期显示在页面中。干得好!

+

如果你保存刚刚创建的 HTML 文件并将其加载到浏览器中,你将看到图像按预期显示在页面中。干得好!

-

注意: 你可能会注意到这些例子有点做作。你可以取消整个fetch()blob()链,只需创建一个<img>元素并将其src属性值设置为图像文件的URL,即coffee.jpg。然而,我们选择了这个例子,因为它以简单的方式展示了promise,而不是真实世界的适当性。

+

注意: 你可能会注意到这些例子有点做作。你可以取消整个fetch()blob()链,只需创建一个<img>元素并将其src属性值设置为图像文件的 URL,即coffee.jpg。然而,我们选择了这个例子,因为它以简单的方式展示了 promise,而不是真实世界的适当性。

响应失败

-

缺少一些东西 - 如果其中一个promise失败(rejects,in promise-speak),目前没有什么可以明确地处理错误。我们可以通过运行前一个promise的 .catch() 方法来添加错误处理。立即添加:

+

缺少一些东西 - 如果其中一个 promise 失败(rejects,in promise-speak),目前没有什么可以明确地处理错误。我们可以通过运行前一个 promise 的 .catch() 方法来添加错误处理。立即添加:

let errorCase = promise3.catch(e => {
   console.log('There has been a problem with your fetch operation: ' + e.message);
 });
-

要查看此操作,请尝试拼错图像的URL并重新加载页面。该错误将在浏览器的开发人员工具的控制台中报告。

+

要查看此操作,请尝试拼错图像的 URL 并重新加载页面。该错误将在浏览器的开发人员工具的控制台中报告。

-

如果你根本不操心包括的 .catch() 块,这并没有做太多的事情,但考虑一下(指.catch()块) ––这会使我们可以完全控制错误处理方式。在真实的应用程序中,你的.catch()块可以重试获取图像,或显示默认图像,或提示用户提供不同的图像URL等等。

+

如果你根本不操心包括的 .catch() 块,这并没有做太多的事情,但考虑一下(指.catch() 块) ––这会使我们可以完全控制错误处理方式。在真实的应用程序中,你的.catch()块可以重试获取图像,或显示默认图像,或提示用户提供不同的图像 URL 等等。

注意: 你可以参考 our version of the example live (参阅 source code ).

@@ -236,7 +236,7 @@

响应失败

将代码块链在一起

-

这是写出来的一种非常简便的方式;我们故意这样做是为了帮助你清楚地了解发生了什么。如本文前面所示,你可以将.then()块(以及.catch()块)链接在一起。上面的代码也可以这样写(参阅GitHub上的simple-fetch-chained.html ):

+

这是写出来的一种非常简便的方式;我们故意这样做是为了帮助你清楚地了解发生了什么。如本文前面所示,你可以将.then()块(以及.catch()块)链接在一起。上面的代码也可以这样写 (参阅 GitHub 上的simple-fetch-chained.html ):

fetch('coffee.jpg')
 .then(response => {
@@ -256,31 +256,31 @@ 

将代码块链在一起

console.log('There has been a problem with your fetch operation: ' + e.message); });
-

请记住,履行的promise所返回的值将成为传递给下一个 .then() 块的executor函数的参数。

+

请记住,履行的 promise 所返回的值将成为传递给下一个 .then() 块的 executor 函数的参数。

-

注意: promise中的.then()/catch()块基本上是同步代码中try...catch块的异步等价物。请记住,同步try ... catch在异步代码中不起作用。

+

注意: promise 中的.then()/catch()块基本上是同步代码中try...catch块的异步等价物。请记住,同步try ... catch在异步代码中不起作用。

-

Promise术语回顾

+

Promise 术语回顾

在上面的部分中有很多要介绍的内容,所以让我们快速回过头来给你一个简短的指南,你可以将它添加到书签中,以便将来更新你的记忆。你还应该再次阅读上述部分,以确保这些概念坚持下去。

    -
  1. 创建promise时,它既不是成功也不是失败状态。这个状态叫作pending(待定)。
  2. -
  3. 当promise返回时,称为 resolved(已解决). +
  4. 创建 promise 时,它既不是成功也不是失败状态。这个状态叫作pending(待定)。
  5. +
  6. 当 promise 返回时,称为 resolved(已解决).
      -
    1. 一个成功resolved的promise称为fullfilled实现)。它返回一个值,可以通过将.then()块链接到promise链的末尾来访问该值。 .then()块中的执行程序函数将包含promise的返回值。
    2. -
    3. 一个不成功resolved的promise被称为rejected拒绝)了。它返回一个原因(reason),一条错误消息,说明为什么拒绝promise。可以通过将.catch()块链接到promise链的末尾来访问此原因。
    4. +
    5. 一个成功resolved的 promise 称为fullfilled实现)。它返回一个值,可以通过将.then()块链接到 promise 链的末尾来访问该值。 .then()块中的执行程序函数将包含 promise 的返回值。
    6. +
    7. 一个不成功resolved的 promise 被称为rejected拒绝)了。它返回一个原因(reason),一条错误消息,说明为什么拒绝 promise。可以通过将.catch()块链接到 promise 链的末尾来访问此原因。
-

 运行代码以响应多个Promises的实现

+

 运行代码以响应多个 Promises 的实现

-

上面的例子向我们展示了使用promises的一些真正的基础知识。现在让我们看一些更高级的功能。首先,链接进程一个接一个地发生都很好,但是如果你想在一大堆Promises全部完成之后运行一些代码呢?

+

上面的例子向我们展示了使用 promises 的一些真正的基础知识。现在让我们看一些更高级的功能。首先,链接进程一个接一个地发生都很好,但是如果你想在一大堆 Promises 全部完成之后运行一些代码呢?

-

 你可以使用巧妙命名的Promise.all()静态方法完成此操作。这将一个promises数组作为输入参数,并返回一个新的Promise对象,只有当数组中的所有promise都满足时才会满足。它看起来像这样:

+

 你可以使用巧妙命名的Promise.all()静态方法完成此操作。这将一个 promises 数组作为输入参数,并返回一个新的 Promise 对象,只有当数组中的所有 promise 都满足时才会满足。它看起来像这样:

Promise.all([a, b, c]).then(values => {
   ...
@@ -288,7 +288,7 @@ 

 运行代码以响应多

如果它们都实现,那么数组中的结果将作为参数传递给.then()块中的执行器函数。如果传递给Promise.all()的任何一个 promise 拒绝,整个块将拒绝

-

这非常有用。想象一下,我们正在获取信息以在内容上动态填充页面上的UI功能。在许多情况下,接收所有数据然后才显示完整内容,而不是显示部分信息。

+

这非常有用。想象一下,我们正在获取信息以在内容上动态填充页面上的 UI 功能。在许多情况下,接收所有数据然后才显示完整内容,而不是显示部分信息。

让我们构建另一个示例来展示这一点。

@@ -297,10 +297,10 @@

 运行代码以响应多

下载我们页面模板(page template)的新副本,并再次在结束</ body>标记之前放置一个<script>元素。

  • -

    下载我们的源文件(coffee.jpg, tea.jpg和 description.txt),或者随意替换成你自己的文件。

    +

    下载我们的源文件 (coffee.jpg, tea.jpg和 description.txt),或者随意替换成你自己的文件。

  • -

    在我们的脚本中,我们将首先定义一个函数,该函数返回我们要发送给Promise.all()的promise。如果我们只想运行Promise.all()块以响应三个fetch()操作完成,这将很容易。我们可以这样做:

    +

    在我们的脚本中,我们将首先定义一个函数,该函数返回我们要发送给Promise.all()的 promise。如果我们只想运行Promise.all()块以响应三个fetch()操作完成,这将很容易。我们可以这样做:

    let a = fetch(url1);
     let b = fetch(url2);
    @@ -310,7 +310,7 @@ 

     运行代码以响应多 ... });

    -

    当promise是fullfilled时,传递到履行处理程序的values将包含三个Response对象,每个对象用于已完成的每个fetch()操作。

    +

    当 promise 是fullfilled时,传递到履行处理程序的values将包含三个 Response 对象,每个对象用于已完成的每个fetch()操作。

    但是,我们不想这样做。我们的代码不关心fetch()操作何时完成。相反,我们想要的是加载的数据。这意味着当我们返回代表图像的可用blob和可用的文本字符串时,我们想要运行Promise.all()块。我们可以编写一个执行此操作的函数;在<script>元素中添加以下内容:

    @@ -330,39 +330,39 @@

     运行代码以响应多

    这看起来有点复杂,所以让我们一步一步地完成它:

      -
    1. 首先,我们定义函数,向它传递一个URL和字符串,这个字符串表示资源类型。
    2. -
    3. 在函数体内部,我们有一个类似于我们在第一个例子中看到的结构 - 我们调用fetch()函数来获取指定URL处的资源,然后将其链接到另一个 promise ,它解码(或“read”)响应body。这是前一个示例中的blob()方法。
    4. +
    5. 首先,我们定义函数,向它传递一个 URL 和字符串,这个字符串表示资源类型。
    6. +
    7. 在函数体内部,我们有一个类似于我们在第一个例子中看到的结构 - 我们调用fetch()函数来获取指定 URL 处的资源,然后将其链接到另一个 promise,它解码(或“read”)响应 body。这是前一个示例中的blob()方法。
    8. 但是,这里有两处不同:
        -
      • 首先,我们返回的第二个promise会因类型值的不同而不同。在执行函数内部,我们包含一个简单的if ... else if语句,根据我们需要解码的文件类型返回不同的promise(在这种情况下,我们可以选择blobtext,而且很容易扩展这个以处理其他类型)。
      • -
      • 其次,我们在fetch()调用之前添加了return关键字。它的作用是运行整个链,然后运行最终结果(即blob()text()返回的promise作为我们刚刚定义的函数的返回值)。实际上,return语句将结果从链返回到顶部。
      • +
      • 首先,我们返回的第二个 promise 会因类型值的不同而不同。在执行函数内部,我们包含一个简单的if ... else if语句,根据我们需要解码的文件类型返回不同的 promise(在这种情况下,我们可以选择blobtext,而且很容易扩展这个以处理其他类型)。
      • +
      • 其次,我们在fetch()调用之前添加了return关键字。它的作用是运行整个链,然后运行最终结果(即blob()text()返回的 promise 作为我们刚刚定义的函数的返回值)。实际上,return语句将结果从链返回到顶部。
    9. -

      在块结束时,我们链接一个.catch()调用,以处理任何可能出现在数组中传递给.all()的任何promise的错误情况。如果任何promise被拒绝,catch块将告诉你哪个promise有问题。 .all()块(见下文)仍然可以实现,但不会显示有问题的资源。如果你想要.all拒绝,你必须将.catch()块链接到那里的末尾。

      +

      在块结束时,我们链接一个.catch()调用,以处理任何可能出现在数组中传递给.all()的任何 promise 的错误情况。如果任何 promise 被拒绝,catch块将告诉你哪个 promise 有问题。 .all()块(见下文)仍然可以实现,但不会显示有问题的资源。如果你想要.all拒绝,你必须将.catch()块链接到那里的末尾。

    -

    函数体内部的代码是async(异步)和基于promise的,因此实际上整个函数就像一个promise ––方便啊!

    +

    函数体内部的代码是 async(异步)和基于 promise 的,因此实际上整个函数就像一个 promise ––方便啊!

  • -

    接下来,我们调用我们的函数三次以开始获取和解码图像和文本的过程,并将每个返回的promises存储在变量中。在以前的代码下面添加以下内容:

    +

    接下来,我们调用我们的函数三次以开始获取和解码图像和文本的过程,并将每个返回的 promises 存储在变量中。在以前的代码下面添加以下内容:

    let coffee = fetchAndDecode('coffee.jpg', 'blob');
     let tea = fetchAndDecode('tea.jpg', 'blob');
     let description = fetchAndDecode('description.txt', 'text');
  • -

    接下来,我们将定义一个Promise.all()块,仅当上面存储的所有三个promise都已成功完成时才运行一些代码。首先,在.then()调用中添加一个带有空执行程序的块,如下所示:

    +

    接下来,我们将定义一个Promise.all()块,仅当上面存储的所有三个 promise 都已成功完成时才运行一些代码。首先,在.then()调用中添加一个带有空执行程序的块,如下所示:

    Promise.all([coffee, tea, description]).then(values => {
     
     });
    -

    你可以看到它需要一个包含promises作为参数的数组。执行者只有在所有三个promises的状态成为resolved时才会运行;当发生这种情况时,它将被传入一个数组,其中包含来自各个promise(即解码的响应主体)的结果,类似于 [coffee-results, tea-results, description-results].

    +

    你可以看到它需要一个包含 promises 作为参数的数组。执行者只有在所有三个 promises 的状态成为resolved时才会运行;当发生这种情况时,它将被传入一个数组,其中包含来自各个 promise(即解码的响应主体)的结果,类似于 [coffee-results, tea-results, description-results].

  • -

    最后,在执行程序中添加以下内容。这里我们使用一些相当简单的同步代码将结果存储在单独的变量中(从blob创建对象URL),然后在页面上显示图像和文本。

    +

    最后,在执行程序中添加以下内容。这里我们使用一些相当简单的同步代码将结果存储在单独的变量中(从 blob 创建对象 URL),然后在页面上显示图像和文本。

    console.log(values);
     // Store each value returned from the promises in separate variables; create object URLs from the blobs
    @@ -384,7 +384,7 @@ 

     运行代码以响应多 document.body.appendChild(para);

  • -

    保存并刷新,你应该看到所有UI组件都已加载,尽管不是特别有吸引力!

    +

    保存并刷新,你应该看到所有 UI 组件都已加载,尽管不是特别有吸引力!

  • @@ -397,12 +397,12 @@

     运行代码以响应多

    注意: 如果你正在改进这段代码,你可能想要遍历一个项目列表来显示,获取和解码每个项目,然后循环遍历Promise.all()内部的结果,运行一个不同的函数来显示每个项目取决于什么代码的类型是。这将使它适用于任何数量的项目,而不仅仅是三个。

    -

    此外,你可以确定要获取的文件类型,而无需显式类型属性。例如,你可以使用response.headers.get("content-type")检查响应的{{HTTPHeader("Content-Type")}} HTTP标头,然后做出相应的反应。

    +

    此外,你可以确定要获取的文件类型,而无需显式类型属性。例如,你可以使用response.headers.get("content-type")检查响应的{{HTTPHeader("Content-Type")}} HTTP 标头,然后做出相应的反应。

    -

     在promise fullfill/reject后运行一些最终代码

    +

     在 promise fullfill/reject后运行一些最终代码

    -

    在promise完成后,你可能希望运行最后一段代码,无论它是否已实现(fullfilled)或被拒绝(rejected)。此前,你必须在.then().catch()回调中包含相同的代码,例如:

    +

    在 promise 完成后,你可能希望运行最后一段代码,无论它是否已实现(fullfilled)或被拒绝(rejected)。此前,你必须在.then().catch()回调中包含相同的代码,例如:

    myPromise
     .then(response => {
    @@ -414,7 +414,7 @@ 

     在promise fullf runFinalCode(); });

    -

    在现代浏览器中,.finally() 方法可用,它可以链接到常规promise链的末尾,允许你减少代码重复并更优雅地执行操作。上面的代码现在可以写成如下:

    +

    在现代浏览器中,.finally() 方法可用,它可以链接到常规 promise 链的末尾,允许你减少代码重复并更优雅地执行操作。上面的代码现在可以写成如下:

    myPromise
     .then(response => {
    @@ -452,20 +452,20 @@ 

     在promise fullf

    这会将一条简单的消息记录到控制台,告诉我们每次获取尝试的时间。

    -

    注意:finally()允许你在异步代码中编写异步等价物try/ catch / finally。

    +

    注意:finally() 允许你在异步代码中编写异步等价物 try/ catch / finally。

    -

     构建自定义promise

    +

     构建自定义 promise

    -

    好消息是,在某种程度上,你已经建立了自己的promise。当你使用.then()块链接多个promise时,或者将它们组合起来创建自定义函数时,你已经在创建自己的基于异步声明的自定义函数。例如,从前面的示例中获取我们的fetchAndDecode()函数。

    +

    好消息是,在某种程度上,你已经建立了自己的 promise。当你使用.then()块链接多个 promise 时,或者将它们组合起来创建自定义函数时,你已经在创建自己的基于异步声明的自定义函数。例如,从前面的示例中获取我们的fetchAndDecode()函数。

    -

    将不同的基于promise的API组合在一起以创建自定义函数是迄今为止你使用promises进行自定义事务的最常见方式,并展示了基于相同原则的大多数现代API的灵活性和强大功能。然而,还有另一种方式。

    +

    将不同的基于 promise 的 API 组合在一起以创建自定义函数是迄今为止你使用 promises 进行自定义事务的最常见方式,并展示了基于相同原则的大多数现代 API 的灵活性和强大功能。然而,还有另一种方式。

    -

    使用Promise()构造函数

    +

    使用 Promise() 构造函数

    -

    可以使用Promise() 构造函数构建自己的promise。当你需要使用现有的旧项目代码、库或框架以及基于现代promise的代码时,这会派上用场。比如,当你遇到没有使用promise的旧式异步API的代码时,你可以用promise来重构这段异步代码。

    +

    可以使用Promise() 构造函数构建自己的 promise。当你需要使用现有的旧项目代码、库或框架以及基于现代 promise 的代码时,这会派上用场。比如,当你遇到没有使用 promise 的旧式异步 API 的代码时,你可以用 promise 来重构这段异步代码。

    -

    让我们看一个简单的示例来帮助你入门 —— 这里我们用 promise 包装一了个setTimeout()它会在两秒后运行一个函数,该函数将用字符串“Success!”,解析当前promise(调用链接的resolve())。

    +

    让我们看一个简单的示例来帮助你入门 —— 这里我们用 promise 包装一了个setTimeout()它会在两秒后运行一个函数,该函数将用字符串“Success!”,解析当前 promise(调用链接的resolve())。

    let timeoutPromise = new Promise((resolve, reject) => {
       setTimeout(function(){
    @@ -473,9 +473,9 @@ 

    使用Promise()构造函数

    }, 2000); });
    -

    resolve()reject()是用来实现拒绝新创建的promise的函数。此处,promise 成功运行通过显示字符串“Success!”。

    +

    resolve()reject()是用来实现拒绝新创建的 promise 的函数。此处,promise 成功运行通过显示字符串“Success!”。

    -

    因此,当你调用此promise时,可以将.then()块链接到它的末尾,它将传递给.then()块一串“Success!”。在下面的代码中,我们显示出该消息:

    +

    因此,当你调用此 promise 时,可以将.then()块链接到它的末尾,它将传递给.then()块一串“Success!”。在下面的代码中,我们显示出该消息:

    timeoutPromise
     .then((message) => {
    @@ -489,15 +489,15 @@ 

    使用Promise()构造函数

    尝试 running this live 以查看结果 (可参考 source code).

    -

    上面的例子不是很灵活 - promise只能实现一个字符串,并且它没有指定任何类型的reject()条件(诚然,setTimeout()实际上没有失败条件,所以对这个简单的例子并不重要)。

    +

    上面的例子不是很灵活 - promise 只能实现一个字符串,并且它没有指定任何类型的reject()条件(诚然,setTimeout()实际上没有失败条件,所以对这个简单的例子并不重要)。

    注意: 为什么要resolve(),而不是fullfill()?我们现在给你的答案有些复杂。

    -

    拒绝一个自定义promise

    +

    拒绝一个自定义 promise

    -

    我们可以创建一个reject() 方法拒绝promise  - 就像resolve()一样,这需要一个值,但在这种情况下,它是拒绝的原因,即将传递给.catch()的错误块。

    +

    我们可以创建一个reject() 方法拒绝 promise  - 就像resolve()一样,这需要一个值,但在这种情况下,它是拒绝的原因,即将传递给.catch()的错误块。

    让我们扩展前面的例子,使其具有一些reject()条件,并允许在成功时传递不同的消息。

    @@ -517,17 +517,17 @@

    拒绝一个自定义promise

    }); };
    -

    在这里,我们将两个方法传递给一个自定义函数 - 一个用来做某事的消息,以及在做这件事之前要经过的时间间隔。在函数内部,我们返回一个新的Promise对象 - 调用该函数将返回我们想要使用的promise。

    +

    在这里,我们将两个方法传递给一个自定义函数 - 一个用来做某事的消息,以及在做这件事之前要经过的时间间隔。在函数内部,我们返回一个新的Promise对象 - 调用该函数将返回我们想要使用的 promise。

    -

    Promise构造函数中,我们在if ... else结构中进行了一些检查:

    +

    Promise构造函数中,我们在 if ... else 结构中进行了一些检查:

      -
    1. 首先,我们检查消息是否适合被警告。如果它是一个空字符串或根本不是字符串,我们会使用合适的错误消息拒绝该promise。
    2. -
    3. 接下来,我们检查间隔是否是适当的间隔值。如果是负数或不是数字,我们会使用合适的错误消息拒绝promise。
    4. -
    5. 最后,如果参数看起来都正常,我们使用setTimeout()在指定的时间间隔过后,使用指定的消息解析promise。
    6. +
    7. 首先,我们检查消息是否适合被警告。如果它是一个空字符串或根本不是字符串,我们会使用合适的错误消息拒绝该 promise。
    8. +
    9. 接下来,我们检查间隔是否是适当的间隔值。如果是负数或不是数字,我们会使用合适的错误消息拒绝 promise。
    10. +
    11. 最后,如果参数看起来都正常,我们使用setTimeout()在指定的时间间隔过后,使用指定的消息解析 promise。
    -

    由于timeoutPromise()函数返回一个Promise,我们可以将.then().catch()等链接到它上面以利用它的功能。现在让我们使用它 - 将以前的timeoutPromise用法替换为以下值:

    +

    由于timeoutPromise()函数返回一个Promise,我们可以将.then().catch()等链接到它上面以利用它的功能。现在让我们使用它 - 将以前的 timeoutPromise 用法替换为以下值:

    timeoutPromise('Hello there!', 1000)
     .then(message => {
    @@ -537,17 +537,17 @@ 

    拒绝一个自定义promise

    console.log('Error: ' + e); });
    -

    当你按原样保存并运行代码时,一秒钟后你将收到消息提醒。现在尝试将消息设置为空字符串或将间隔设置为负数,例如,你将能够通过相应的错误消息查看被拒绝的promise!你还可以尝试使用已解决的消息执行其他操作,而不仅仅是提醒它。

    +

    当你按原样保存并运行代码时,一秒钟后你将收到消息提醒。现在尝试将消息设置为空字符串或将间隔设置为负数,例如,你将能够通过相应的错误消息查看被拒绝的 promise!你还可以尝试使用已解决的消息执行其他操作,而不仅仅是提醒它。

    -

    注意: 你可以在GitHub上找到我们的这个示例版本custom-promise2.html(另请参阅source code)。

    +

    注意: 你可以在 GitHub 上找到我们的这个示例版本custom-promise2.html(另请参阅source code)。

    一个更真实的例子

    -

    上面的例子是故意做得简单,以使概念易于理解,但它并不是实际上完全异步。异步性质基本上是使用setTimeout()伪造的,尽管它仍然表明promises对于创建具有合理的操作流程,良好的错误处理等的自定义函数很有用

    +

    上面的例子是故意做得简单,以使概念易于理解,但它并不是实际上完全异步。异步性质基本上是使用setTimeout()伪造的,尽管它仍然表明 promises 对于创建具有合理的操作流程,良好的错误处理等的自定义函数很有用

    -

    我们想邀请你学习的一个例子是Jake Archibald's idb library,它真正地显示了Promise()构造函数的有用异步应用程序。这采用了 IndexedDB API,它是一种旧式的基于回调的API,用于在客户端存储和检索数据,并允许你将其与promises一起使用。如果你查看main library file,你将看到我们在上面讨论过的相同类型的技术。以下块将许多IndexedDB方法使用的基本请求模型转换为使用promise:

    +

    我们想邀请你学习的一个例子是Jake Archibald's idb library,它真正地显示了Promise()构造函数的有用异步应用程序。这采用了 IndexedDB API,它是一种旧式的基于回调的 API,用于在客户端存储和检索数据,并允许你将其与 promises 一起使用。如果你查看main library file,你将看到我们在上面讨论过的相同类型的技术。以下块将许多 IndexedDB 方法使用的基本请求模型转换为使用 promise:

    function promisifyRequest(request) {
       return new Promise(function(resolve, reject) {
    @@ -565,18 +565,18 @@ 

    一个更真实的例子

    总结

    -

    当我们不知道函数的返回值或返回需要多长时间时,Promises是构建异步应用程序的好方法。它们使得在没有深度嵌套回调的情况下更容易表达和推理异步操作序列,并且它们支持类似于同步try ... catch语句的错误处理方式。

    +

    当我们不知道函数的返回值或返回需要多长时间时,Promises 是构建异步应用程序的好方法。它们使得在没有深度嵌套回调的情况下更容易表达和推理异步操作序列,并且它们支持类似于同步try ... catch语句的错误处理方式。

    -

    Promise适用于所有现代浏览器的最新版本;promise有兼容问题的唯一情况是Opera Mini和IE11及更早版本。

    +

    Promise 适用于所有现代浏览器的最新版本;promise 有兼容问题的唯一情况是 Opera Mini 和 IE11 及更早版本。

    -

    本文中,我们没有涉及的所有promise的功能,只是最有趣和最有用的功能。当你开始了解有关promise的更多信息时,你会遇到更多功能和技巧。

    +

    本文中,我们没有涉及的所有 promise 的功能,只是最有趣和最有用的功能。当你开始了解有关 promise 的更多信息时,你会遇到更多功能和技巧。

    -

    大多数现代Web API都是基于promise的,因此你需要了解promise才能充分利用它们。这些API包括WebRTCWeb Audio APIMedia Capture and Streams等等。随着时间的推移,Promises将变得越来越重要,因此学习使用和理解它们是学习现代JavaScript的重要一步。

    +

    大多数现代 Web API 都是基于 promise 的,因此你需要了解 promise 才能充分利用它们。这些 API 包括WebRTCWeb Audio APIMedia Capture and Streams等等。随着时间的推移,Promises 将变得越来越重要,因此学习使用和理解它们是学习现代 JavaScript 的重要一步。

    参见

    @@ -592,9 +592,9 @@

     本章内容

    diff --git a/files/zh-cn/learn/javascript/building_blocks/build_your_own_function/index.html b/files/zh-cn/learn/javascript/building_blocks/build_your_own_function/index.html index 473e322163f4ff..2ca940b69e2d4f 100644 --- a/files/zh-cn/learn/javascript/building_blocks/build_your_own_function/index.html +++ b/files/zh-cn/learn/javascript/building_blocks/build_your_own_function/index.html @@ -19,7 +19,7 @@ 先修知识: - 基本的电脑常识,对于HTML和CSS的基本了解, JavaScript第一步函数-可复用代码块。 + 基本的电脑常识,对于 HTML 和 CSS 的基本了解, JavaScript 第一步函数 - 可复用代码块。 目标: @@ -30,7 +30,7 @@

    先活跃下气氛:构建一个函数

    -

    我们将构建的传统函数将被命名为 displayMessage(),它向用户展示一个传统的消息盒子于web页面的顶部。它充当浏览器内建的 alert() 函数更有用的替代品。你已经看过了这个,但是我们回复一下我们的记忆——在你的浏览器的 JavaScript控制台中,在任意一个页面里尝试以下代码

    +

    我们将构建的传统函数将被命名为 displayMessage(),它向用户展示一个传统的消息盒子于 web 页面的顶部。它充当浏览器内建的 alert() 函数更有用的替代品。你已经看过了这个,但是我们回复一下我们的记忆——在你的浏览器的 JavaScript 控制台中,在任意一个页面里尝试以下代码

    alert('This is a message');
    @@ -39,7 +39,7 @@

    先活跃下气氛:构建一

    这个alert()函数不是很好的:您可以alert()出这条信息,但是您不能很容易的表达其他内容,例如颜色,图标或者是其他东西。接下来我们将会构建一个更有趣的函数。

    -

    笔记: 这个例子能够在现代浏览器上很好的工作,但是这个风格在老的浏览器上并没那么有趣。我们建议你实现这个例子时在现代浏览器上,例如Firefox,Opera或者Chrome浏览器。

    +

    笔记: 这个例子能够在现代浏览器上很好的工作,但是这个风格在老的浏览器上并没那么有趣。我们建议你实现这个例子时在现代浏览器上,例如 Firefox,Opera 或者 Chrome 浏览器。

    基本函数

    @@ -47,11 +47,11 @@

    基本函数

    首先,让我们来组织一个基本的函数。

    -

    注:对于函数命名约定,应遵循与变量命名约定相同的规则。 这很好,尽你所能理解它们之间的区别 - 函数名称后带有括号,而变量则没有。

    +

    注:对于函数命名约定,应遵循与变量命名约定相同的规则。这很好,尽你所能理解它们之间的区别 - 函数名称后带有括号,而变量则没有。

      -
    1. 我们希望您首先访问function-start.html文件并创建一个本地拷贝。您将会看到这个HTML很简单 — 我们的body块仅包含一个按钮。我们还提供了一些基本的CSS来装饰自定义消息框,以及一个用于放置JavaScript代码的{{htmlelement("script")}}元素。
    2. +
    3. 我们希望您首先访问function-start.html文件并创建一个本地拷贝。您将会看到这个 HTML 很简单 — 我们的 body 块仅包含一个按钮。我们还提供了一些基本的 CSS 来装饰自定义消息框,以及一个用于放置 JavaScript 代码的{{htmlelement("script")}}元素。
    4. 接下来,将下面的代码添加至 <script> 元素中:
      function displayMessage() {
       
      @@ -80,21 +80,21 @@ 

      基本函数

      天哪,这么多代码!好吧,一行一行的解释给你听。

      -

      第一行代码使用了一个DOM(文档对象模型)的内置方法 {{domxref("document.querySelector()")}} 来选择{{htmlelement("html")}} 元素并且把它存放在一个叫 html的常量中, 这样方便我们接下来使用这个元素:

      +

      第一行代码使用了一个 DOM(文档对象模型)的内置方法 {{domxref("document.querySelector()")}} 来选择{{htmlelement("html")}} 元素并且把它存放在一个叫 html的常量中,这样方便我们接下来使用这个元素:

      const html = document.querySelector('html');
      -

      下段代码使用了另一个名字叫做 {{domxref("Document.createElement()")}} 的DOM方法,用来创建 {{htmlelement("div")}} 元素并且把该新建元素的引用(实际上是新建对象的地址)放在一个叫做 panel的常量中。 这个元素将成为我们的消息框的外部容器。

      +

      下段代码使用了另一个名字叫做 {{domxref("Document.createElement()")}} 的 DOM 方法,用来创建 {{htmlelement("div")}} 元素并且把该新建元素的引用(实际上是新建对象的地址)放在一个叫做 panel的常量中。 这个元素将成为我们的消息框的外部容器。

      -

      然后我们又使用了一个叫做 {{domxref("Element.setAttribute()")}} 的DOM方法给panel元素添加了一个值为msgBox 的class 类属性。 这样做方便我们来给这个元素添加样式 — 查看CSS代码你就知道我们使用.msgBox 类选择器来给消息框和消息内容设置样式。

      +

      然后我们又使用了一个叫做 {{domxref("Element.setAttribute()")}} 的 DOM 方法给 panel 元素添加了一个值为msgBox 的class 类属性。 这样做方便我们来给这个元素添加样式 — 查看 CSS 代码你就知道我们使用.msgBox 类选择器来给消息框和消息内容设置样式。

      -

      最后,我们还使用了一个叫做 {{domxref("Node.appendChild()")}} 的DOM方法,给 html 常量(我们之前定义好的)追加了我们设置好样式的panel元素 。该方法追加了元素的同时也把panel<div>元素指定为<html>的子元素 。这样做是因为我们创建了一个元素之后这个元素并不会莫名其妙的出现在我们的页面上(浏览器只知道我们创建了一个元素,但是不知道把这个元素怎么呈现出来) — 因此,我们给这个元素了一个定位,就是显示在html里面!

      +

      最后,我们还使用了一个叫做 {{domxref("Node.appendChild()")}} 的 DOM 方法,给 html 常量(我们之前定义好的)追加了我们设置好样式的 panel 元素 。该方法追加了元素的同时也把 panel<div>元素指定为<html>的子元素 。这样做是因为我们创建了一个元素之后这个元素并不会莫名其妙的出现在我们的页面上(浏览器只知道我们创建了一个元素,但是不知道把这个元素怎么呈现出来) — 因此,我们给这个元素了一个定位,就是显示在 html 里面!

      const panel = document.createElement('div');
       panel.setAttribute('class', 'msgBox');
       html.appendChild(panel);
      -

      下面这两段使用了我们之前使用过的方法createElement()appendChild()  — 创建了一个 {{htmlelement("p")}}  元素和一个{{htmlelement("button")}}元素 —  并且把他们追加到了panel<div>之下。我们使用元素的 {{domxref("Node.textContent")}}(Node泛指一个元素并不是说是某个元素是叫Node) 属性— 表示一个元素的文本属性 — 给一个p元素赋值, 同样按钮也有这个属性,该属性就是按钮显示的‘X’。这个按钮的功能就是关闭消息提示框。

      +

      下面这两段使用了我们之前使用过的方法createElement()appendChild()  — 创建了一个 {{htmlelement("p")}}  元素和一个{{htmlelement("button")}}元素 —  并且把他们追加到了 panel<div>之下。我们使用元素的 {{domxref("Node.textContent")}}(Node 泛指一个元素并不是说是某个元素是叫 Node)属性— 表示一个元素的文本属性 — 给一个 p 元素赋值,同样按钮也有这个属性,该属性就是按钮显示的‘X’。这个按钮的功能就是关闭消息提示框。

      const msg = document.createElement('p');
       msg.textContent = 'This is a message box';
      @@ -104,45 +104,45 @@ 

      基本函数

      closeBtn.textContent = 'x'; panel.appendChild(closeBtn);
      -

      最后我们使用一个叫做 {{domxref("GlobalEventHandlers.onclick")}} 的事件句柄给按钮添加了一个点击事件, 点击事件后定义了一个匿名函数,功能是将消息提示框从父容器中删除 — 达到了关闭的效果。

      +

      最后我们使用一个叫做 {{domxref("GlobalEventHandlers.onclick")}} 的事件句柄给按钮添加了一个点击事件,点击事件后定义了一个匿名函数,功能是将消息提示框从父容器中删除 — 达到了关闭的效果。

      -

      简单来说,这个 onclick 句柄是一个按钮的属性 (事实上,页面上的任何元素) 当按钮被点击的时候能够执行一些代码。 你可以在之后的介绍事件的章节了解详情。我们给 onclick 句柄绑定了一个匿名函数, 函数中代码在元素被点击的时候运行。函数里面的这行代码使用了 {{domxref("Node.removeChild()")}} DOM 方法指定了我们想要移除的HTML的子元素 — 在这里指panel<div>.

      +

      简单来说,这个 onclick 句柄是一个按钮的属性 (事实上,页面上的任何元素) 当按钮被点击的时候能够执行一些代码。 你可以在之后的介绍事件的章节了解详情。我们给 onclick 句柄绑定了一个匿名函数,函数中代码在元素被点击的时候运行。函数里面的这行代码使用了 {{domxref("Node.removeChild()")}} DOM 方法指定了我们想要移除的 HTML 的子元素 — 在这里指 panel<div>.

      -

      PS:我来解释下是什么意思,panel是消息框,panel.parentNode就是指panel的上一级,就是整个DOM,然后再来用这个父亲来干掉这个儿子,儿子不能自己干掉自己,所以要这么做。

      +

      PS:我来解释下是什么意思,panel 是消息框,panel.parentNode 就是指 panel 的上一级,就是整个 DOM,然后再来用这个父亲来干掉这个儿子,儿子不能自己干掉自己,所以要这么做。

      closeBtn.onclick = function() {
         panel.parentNode.removeChild(panel);
       }
      -

      大体上, 这一整块的代码我就不解释了就是一个div,一个段落,一个按钮, 把这个加在页面上:

      +

      大体上,这一整块的代码我就不解释了就是一个 div,一个段落,一个按钮,把这个加在页面上:

      <div class="msgBox">
         <p>This is a message box</p>
         <button>x</button>
       </div>
      -

      啊,看完了这么多代码,是不是很累? — 不用担心,你现在没有必要完全知道这些代码的细节! 这里我们只关心函数的结构和使用方式, 下面的例子将展示一些有意思的东西。

      +

      啊,看完了这么多代码,是不是很累? — 不用担心,你现在没有必要完全知道这些代码的细节!这里我们只关心函数的结构和使用方式, 下面的例子将展示一些有意思的东西。

      调用函数

      -

      相信你已经迫不及待的在你的<script> 标签中写好了一个函数, 但仅仅是定义而已,这玩意不会做任何事情。

      +

      相信你已经迫不及待的在你的<script> 标签中写好了一个函数,但仅仅是定义而已,这玩意不会做任何事情。

        -
      1. 把下面这行代码加在写好的函数下面来调用函数(当然,不一定要放在函数下面来调用,在C语言中确实是还要先定义后使用,但是我们现在用的是JavaScript,这玩意很强大,不管你是先定义后调用还是先调用后定义都行,但是别忘了定义): +
      2. 把下面这行代码加在写好的函数下面来调用函数(当然,不一定要放在函数下面来调用,在 C 语言中确实是还要先定义后使用,但是我们现在用的是 JavaScript,这玩意很强大,不管你是先定义后调用还是先调用后定义都行,但是别忘了定义):
        displayMessage();
        - 这行代码调用了你写的函数, 当浏览器解析到这行代码时会立即执行函数内的代码。当你保存好你的代码以后在浏览器中刷新, 你会马上看到一个小小的提示框弹出来, 但是只弹出了一次。毕竟我们只调用了一次函数是不?
      3. + 这行代码调用了你写的函数,当浏览器解析到这行代码时会立即执行函数内的代码。当你保存好你的代码以后在浏览器中刷新,你会马上看到一个小小的提示框弹出来,但是只弹出了一次。毕竟我们只调用了一次函数是不?
      4. -

        现在打开浏览器开发工具, 找到JavaScript控制台把上面这一句再输入一遍然后回车, 你会看到又弹出了一次!有点意思... — 现在我们有了一个能够重复调用的函数,只要你高兴可以随时调用它。

        +

        现在打开浏览器开发工具,找到 JavaScript 控制台把上面这一句再输入一遍然后回车,你会看到又弹出了一次!有点意思... — 现在我们有了一个能够重复调用的函数,只要你高兴可以随时调用它。

        -

        但是,这玩意有什么用呢?在真实的应用当中这样的消息提示框一般用来提示一些什么新的东西, 或者是出现了一个什么错误, 或者当用户删除配置文件的时候("你确定要这样做?"), 或者用户添加一个新的联系人之后提示操作成功..等等。 在这个例子里面, 当用户点击这个按钮的时候这个提示框会出现。

        +

        但是,这玩意有什么用呢?在真实的应用当中这样的消息提示框一般用来提示一些什么新的东西,或者是出现了一个什么错误,或者当用户删除配置文件的时候 ("你确定要这样做?"), 或者用户添加一个新的联系人之后提示操作成功..等等。在这个例子里面,当用户点击这个按钮的时候这个提示框会出现。

      5. 删掉你之前加的那一行代码。
      6. -
      7. 下一步我们用选择器找到这个按钮并赋值给一个常量。 在你的函数定义之前把这行代码加上去: +
      8. 下一步我们用选择器找到这个按钮并赋值给一个常量。 在你的函数定义之前把这行代码加上去:
        const btn = document.querySelector('button');
      9. -
      10. 最后,把这行代码加在上面这行的下面: +
      11. 最后,把这行代码加在上面这行的下面:
        btn.onclick = displayMessage;
        - 跟关闭按钮类似closeBtn.onclick... , 当按钮被点击的时候我们运行了点代码。 但不同的是, 之前等号的右边是一个匿名函数,看起来是这样的:btn.onclick = function(){...}, 我们现在是直接使用函数名称来调用。
      12. + 跟关闭按钮类似closeBtn.onclick... , 当按钮被点击的时候我们运行了点代码。 但不同的是,之前等号的右边是一个匿名函数,看起来是这样的:btn.onclick = function(){...}, 我们现在是直接使用函数名称来调用。
      13. 保存好以后刷新页面 — 现在你应该能看到当你点击按钮的时候提示框弹出来。
      @@ -150,13 +150,13 @@

      调用函数

      btn.onclick = displayMessage();
      -

      保存刷新, 你会发现按钮都还没点击提示框就出来了! 在函数名后面的这个括号叫做“函数调用运算符”(function invocation operator)。你只有在想直接调用函数的地方才这么写。 同样要重视的是, 匿名函数里面的代码也不是直接运行的, 只要代码在函数作用域内。

      +

      保存刷新,你会发现按钮都还没点击提示框就出来了! 在函数名后面的这个括号叫做“函数调用运算符”(function invocation operator)。你只有在想直接调用函数的地方才这么写。 同样要重视的是,匿名函数里面的代码也不是直接运行的,只要代码在函数作用域内。

      -

      如果你做了这个函数括号的实验, 在继续之前把代码恢复到之前的状态。

      +

      如果你做了这个函数括号的实验,在继续之前把代码恢复到之前的状态。

      使用参数列表改进函数

      -

      就现在看来,我们的函数还不是特别有用 — 我们想要的不仅仅是每点击一次展示一个默认的消息。我们来改造下我们的函数,给它添加几个参数, 允许我们以不同的方式调用这个函数。

      +

      就现在看来,我们的函数还不是特别有用 — 我们想要的不仅仅是每点击一次展示一个默认的消息。我们来改造下我们的函数,给它添加几个参数,允许我们以不同的方式调用这个函数。

      1. 第一步,修改函数的第一行代码: @@ -166,46 +166,46 @@

        使用参数列表改进函数

        function displayMessage(msgText, msgType) {
        当我们调用函数的时候,我们可以在括号里添加两个变量,来指定显示在消息框里面的消息,和消息的类型。
      2. -
      3. 为了使用第一个参数, 把接下来的一行: +
      4. 为了使用第一个参数,把接下来的一行:
        msg.textContent = 'This is a message box';
        -

        改成这样:

        +

        改成这样:

        msg.textContent = msgText;
      5. -
      6. 最后但同样重要的一点, 我们来调用这个函数,并且使用了带参数的形式,修改下面这行: +
      7. 最后但同样重要的一点,我们来调用这个函数,并且使用了带参数的形式,修改下面这行:
        btn.onclick = displayMessage;
        -

        改成这样:

        +

        改成这样:

        btn.onclick = function() {
           displayMessage('Woo, this is a different message!');
         };
        如果我们要在点击事件里面绑定这个新函数,我们不能直接使用(btn.onclick = displayMessage('Woo, this is a different message!');)前面已经讲过— 我们要把它放在一个匿名函数里面,不然函数会直接调用,而不是按钮点击之后才会调用,这不是我们想要的结果。
      8. -
      9. 保存刷新, 就像你所期待的那样现在你可以随意的指定消息框里面显示的消息!
      10. +
      11. 保存刷新,就像你所期待的那样现在你可以随意的指定消息框里面显示的消息!

      一个更加复杂的参数

      -

      刚才我们只使用了我们定义的第一个参数msgText,对于第二个参数msgType,这个就涉及了稍微多一点的东西— 我们要设置一些依赖于这个 msgType 参数的东西, 我们的函数将会显示不同的图标和不同的背景颜色。

      +

      刚才我们只使用了我们定义的第一个参数msgText,对于第二个参数msgType,这个就涉及了稍微多一点的东西— 我们要设置一些依赖于这个 msgType 参数的东西,我们的函数将会显示不同的图标和不同的背景颜色。

        -
      1. 第一步, 从Github上下载我们需要的图标 (警告图标 和 聊天图标) 。 把图标保存在一个叫做icons 的文件夹下,和你的HTML文件在同一个目录下。 +
      2. 第一步,从 Github 上下载我们需要的图标 (警告图标 和 聊天图标) 。把图标保存在一个叫做icons 的文件夹下,和你的 HTML 文件在同一个目录下。 -
        笔记: 警告和聊天图标是在这个网站iconfinder.com上找到的, 设计者是 Nazarrudin Ansyari. 感谢他!
        +
        笔记: 警告和聊天图标是在这个网站 iconfinder.com 上找到的,设计者是 Nazarrudin Ansyari. 感谢他!
      3. -
      4. 下一步, 找到页面的CSS文件. 我们要修改下以便我们使用图标. 首先, 修改 .msgBox 的宽度: +
      5. 下一步,找到页面的 CSS 文件。我们要修改下以便我们使用图标。首先,修改 .msgBox 的宽度:
        width: 200px;
        改成:
        width: 242px;
      6. -
      7. 下一步, 在 .msgBox p { ... } 里面添加几条新规则: +
      8. 下一步,在 .msgBox p { ... } 里面添加几条新规则:
        padding-left: 82px;
         background-position: 25px center;
         background-repeat: no-repeat;
      9. -
      10. CSS改完了以后我们就要来修改函数 displayMessage() 让它能够显示图标. 在你的函数结束符之前}添加下面这几行代码: +
      11. CSS 改完了以后我们就要来修改函数 displayMessage() 让它能够显示图标。在你的函数结束符之前}添加下面这几行代码:
        if (msgType === 'warning') {
           msg.style.backgroundImage = 'url(icons/warning.png)';
           panel.style.backgroundColor = 'red';
        @@ -215,11 +215,11 @@ 

        一个更加复杂的参数

        } else { msg.style.paddingLeft = '20px'; }
        - 来解释下, 如果第二个参数 msgType 的值为 'warning', 我们的消息框将显示一个警告图标和一个红色的背景. 如果这个参数的值是 'chat', 将显示聊天图标和水蓝色的背景. 如果 msgType 没有指定任何值 (或者不是'warning''chat'), 然后这个 else { ... } 代码块将会被执行, 代码的意思是给消息段落设置了一个简单的左内边距并且没有图标, 也没有背景颜色。这么做是为了当没有提供 msgType 参数的时候给函数一个默认行为, 意思是这是一个可选参数(你没发现?其实我们已经用过了!就在这里btn.onclick = function() { displayMessage('Woo, this is a different message!'); };只是当时我们没有写这个else段,也就是啥操作也没做)!
      12. -
      13. 现在来测试下我们的新函数, 可以直接调用 displayMessage() 像这样: + 来解释下,如果第二个参数 msgType 的值为 'warning', 我们的消息框将显示一个警告图标和一个红色的背景。如果这个参数的值是 'chat', 将显示聊天图标和水蓝色的背景。如果 msgType 没有指定任何值 (或者不是'warning''chat'), 然后这个 else { ... } 代码块将会被执行,代码的意思是给消息段落设置了一个简单的左内边距并且没有图标,也没有背景颜色。这么做是为了当没有提供 msgType 参数的时候给函数一个默认行为,意思是这是一个可选参数(你没发现?其实我们已经用过了!就在这里btn.onclick = function() { displayMessage('Woo, this is a different message!'); };只是当时我们没有写这个else段,也就是啥操作也没做)!
      14. +
      15. 现在来测试下我们的新函数,可以直接调用 displayMessage() 像这样:
        displayMessage('Woo, this is a different message!');
        -

        或者这样:

        +

        或者这样:

        displayMessage('Your inbox is almost full — delete some mails', 'warning');
         displayMessage('Brian: Hi there, how are you today?','chat');
        @@ -227,7 +227,7 @@

        一个更加复杂的参数

      -

      注意: 如果你写这个例子遇到了困难, 在这里查看免费的代码 完整版本的代码 (或者在线运行的完整代码), 也可以向我们寻求帮助。

      +

      注意: 如果你写这个例子遇到了困难,在这里查看免费的代码 完整版本的代码 (或者在线运行的完整代码), 也可以向我们寻求帮助。

      测试你的技能!

      @@ -236,7 +236,7 @@

      测试你的技能!

      结论

      -

      恭喜你,终于到了这里(等你好久了)! 这篇文章介绍了如何写一个自定义函数, 要把这个新技能在真实项目中使用上你可能还要花点功夫。 下一篇文章中我们将会介绍函数的另一个相关概念 — 返回值。

      +

      恭喜你,终于到了这里(等你好久了)! 这篇文章介绍了如何写一个自定义函数,要把这个新技能在真实项目中使用上你可能还要花点功夫。 下一篇文章中我们将会介绍函数的另一个相关概念 — 返回值。

      @@ -248,7 +248,7 @@

      在这个模块中

      • 在代码中做决定 - 条件语句 在 Wiki 中编辑
      • 循环吧代码
      • -
      • 函数-可复用代码块
      • +
      • 函数 - 可复用代码块
      • 创建您自己的函数
      • 函数返回值
      • 事件介绍
      • diff --git a/files/zh-cn/learn/javascript/building_blocks/conditionals/index.html b/files/zh-cn/learn/javascript/building_blocks/conditionals/index.html index a2fe29ec75674f..24fd040cfa95ce 100644 --- a/files/zh-cn/learn/javascript/building_blocks/conditionals/index.html +++ b/files/zh-cn/learn/javascript/building_blocks/conditionals/index.html @@ -7,17 +7,17 @@
        {{NextMenu("Learn/JavaScript/Building_blocks/Looping_code", "Learn/JavaScript/Building_blocks")}}
        -

        在任何的编程语言中,代码需要依靠不同的输入作出决定并且采取行动。例如,在游戏中,如果玩家的生命值变成了0,那么游戏就结束了。在天气应用中,如果在早晨运行,就显示一张日出的图片;如果在晚上,就显示星星和月亮的图片。在这篇文章中,我们将探索在JavaScript中所谓的条件语句是怎样工作的。

        +

        在任何的编程语言中,代码需要依靠不同的输入作出决定并且采取行动。例如,在游戏中,如果玩家的生命值变成了 0,那么游戏就结束了。在天气应用中,如果在早晨运行,就显示一张日出的图片;如果在晚上,就显示星星和月亮的图片。在这篇文章中,我们将探索在 JavaScript 中所谓的条件语句是怎样工作的。

        - + - +
        预备知识:基本的计算机知识,对HTML和CSS有基本的了解,JavaScript的第一步基本的计算机知识,对 HTML 和 CSS 有基本的了解,JavaScript 的第一步
        目标:了解怎样在JavaScript中使用条件语句的结构。了解怎样在 JavaScript 中使用条件语句的结构。
        @@ -26,7 +26,7 @@

        只需一个条件你就

        人类(以及其他的动物)无时无刻不在做决定,这些决定都影响着他们的生活,从小事(“我应该吃一片还是两片饼干”)到重要的大事(“我应该留在我的祖国,在我父亲的农场工作;还是应该去美国学习天体物理学”)。

        -

        条件语句结构允许我们来描述在JavaScript中这样的选择,从不得不作出的选择(例如:“一片还是两片”)到产生的结果或这些选择(也许是“吃一片饼干”可能会“仍然感觉饿”,或者是“吃两片饼干”可能会“感觉饱了,但妈妈会因为我吃掉了所有的饼干而骂我”。)

        +

        条件语句结构允许我们来描述在 JavaScript 中这样的选择,从不得不作出的选择(例如:“一片还是两片”)到产生的结果或这些选择(也许是“吃一片饼干”可能会“仍然感觉饿”,或者是“吃两片饼干”可能会“感觉饱了,但妈妈会因为我吃掉了所有的饼干而骂我”。)

        @@ -36,7 +36,7 @@

        if ... else 语句

        基本的的 if…else 语法

        -

        基本的if…else语法看起来像下面的 {{glossary("伪代码")}}:

        +

        基本的 if…else 语法看起来像下面的 {{glossary("伪代码")}}:

        if (condition) {
           code to run if condition is true
        @@ -48,15 +48,15 @@ 

        基本的的 if…else 语法

        1. 关键字 if,并且后面跟随括号。
        2. -
        3. 要测试的条件,放到括号里(通常是“这个值大于另一个值吗”或者“这个值存在吗”)。这个条件会利用比较运算符(我们会在最后的模块中讨论)进行比较,并且返回true或者false。
        4. -
        5. 一组花括号,在里面我们有一些代码——可以是任何我们喜欢的代码,并且只会在条件语句返回true的时候运行。
        6. -
        7. 关键字else。
        8. -
        9. 另一组花括号,在里面我们有一些代码——可以是任何我们喜欢的代码,并且当条件语句返回值不是true的话,它才会运行。
        10. +
        11. 要测试的条件,放到括号里(通常是“这个值大于另一个值吗”或者“这个值存在吗”)。这个条件会利用比较运算符(我们会在最后的模块中讨论)进行比较,并且返回 true 或者 false。
        12. +
        13. 一组花括号,在里面我们有一些代码——可以是任何我们喜欢的代码,并且只会在条件语句返回 true 的时候运行。
        14. +
        15. 关键字 else。
        16. +
        17. 另一组花括号,在里面我们有一些代码——可以是任何我们喜欢的代码,并且当条件语句返回值不是 true 的话,它才会运行。
        -

        这段代码真的非常易懂——它说“如果(if)条件(condition)返回true,运行代码A,否则(else)运行代码B”

        +

        这段代码真的非常易懂——它说“如果(if)条件(condition)返回 true,运行代码 A,否则(else)运行代码 B”

        -

        注意:你不一定需要else和第二个花括号——下面的代码也是符合语法规则的:

        +

        注意:你不一定需要 else 和第二个花括号——下面的代码也是符合语法规则的:

        if (condition) {
           code to run if condition is true
        @@ -64,7 +64,7 @@ 

        基本的的 if…else 语法

        run some other code
        -

        不过,这里你需要注意——在这种情况下,第二段代码不被条件语句控制,所以它总会运行,不管条件返回的是true还是false。这不一定是一件坏事,但这可能不是你想要的——你经常只想要运行一段代码或者另一段,而不是两个都运行。

        +

        不过,这里你需要注意——在这种情况下,第二段代码不被条件语句控制,所以它总会运行,不管条件返回的是 true 还是 false。这不一定是一件坏事,但这可能不是你想要的——你经常只想要运行一段代码或者另一段,而不是两个都运行。

        最后,有时候你可能会看到 if…else 语句没有写花括号,像下面的速记风格:

        @@ -75,7 +75,7 @@

        基本的的 if…else 语法

        一个真实的例子

        -

        为了更好的理解这种语法,让我们考虑一个真实的例子。想像一个孩子被他的父母要求帮助他们做家务。父母可能会说“嗨,宝贝儿,如果你帮我去购物,我会给你额外的零花钱,这样你就能买得起你想要的玩具了。”在JavaScript中,我们可以这样表示:

        +

        为了更好的理解这种语法,让我们考虑一个真实的例子。想像一个孩子被他的父母要求帮助他们做家务。父母可能会说“嗨,宝贝儿,如果你帮我去购物,我会给你额外的零花钱,这样你就能买得起你想要的玩具了。”在 JavaScript 中,我们可以这样表示:

        var shoppingDone = false;
         
        @@ -88,7 +88,7 @@ 

        一个真实的例子

        这段代码显示的结果是变量 shoppingDone 总是返回 false, 意味着对我们的穷孩子来说很失望。如果孩子去购物的话,就需要依靠我们提供机制来使父母把变量 shoppingDone 变成 true

        -

        Note: 你可以看到在Github上这个例子的完整版本(也可以在线运行

        +

        Note: 你可以看到在Github 上这个例子的完整版本(也可以在线运行

        else if

        @@ -135,9 +135,9 @@

        else if

        1. 这里我们有 HTML {{htmlelement("select")}} 元素让我们选择不同的天气,以及一个简单的段落。
        2. -
        3. 在 JavaScript 中, 我们同时存储了对 {{htmlelement("select")}} 和 {{htmlelement("p")}} 的引用, 并对 <select> 添加了一个事件监听器,因此,当它的值改变时,setWeather()函数被执行。
        4. +
        5. 在 JavaScript 中,我们同时存储了对 {{htmlelement("select")}} 和 {{htmlelement("p")}} 的引用,并对 <select> 添加了一个事件监听器,因此,当它的值改变时,setWeather()函数被执行。
        6. 当函数运行时,我们首先新建了一个 choice 变量去存储当前被选的 <select> 中的值。接着我们用条件判断语句根据 choice 的值选择性的展示段落中的文本。注意 else if() {...}段中的条件是怎么被判断的,除了第一个,它是在 if() {...}中被判断的。
        7. -
        8. 最后一个 else {...} 中的选择通常被叫做 “最后招数”  — 在所有的条件都不为 true 时其中的代码会被执行。在这个例子中,如果用户没有选择任何一个选项,它会将段落中的文本清空,例如当用户决定重新选择最开始出现的"--Make a choice--"选项时,就会有这样的效果。
        9. +
        10. 最后一个 else {...} 中的选择通常被叫做“最后招数”  — 在所有的条件都不为 true 时其中的代码会被执行。在这个例子中,如果用户没有选择任何一个选项,它会将段落中的文本清空,例如当用户决定重新选择最开始出现的"--Make a choice--"选项时,就会有这样的效果。
        @@ -158,7 +158,7 @@

        关于比较运算符

        Note: 如果你想复习这些内容,可以回顾之前链接上的材料。

        -

        我们想特别提到测试布尔值(true / false),和一个通用模式,你会频繁遇到它,任何不是 false, undefined, null, 0, NaN 的值,或一个空字符串('')在作为条件语句进行测试时实际返回true,因此您可以简单地使用变量名称来测试它是否为真,甚至是否存在(即它不是未定义的)。例如: 

        +

        我们想特别提到测试布尔值(true / false),和一个通用模式,你会频繁遇到它,任何不是 false, undefined, null, 0, NaN 的值,或一个空字符串('')在作为条件语句进行测试时实际返回 true,因此您可以简单地使用变量名称来测试它是否为真,甚至是否存在(即它不是未定义的)。例如: 

        var cheese = 'Cheddar';
         
        @@ -178,9 +178,9 @@ 

        关于比较运算符

        var childsAllowance = 5; }
        -

        嵌套if ... else

        +

        嵌套 if ... else

        -

        将另一个if ... else 语句放在另一个中 - 嵌套它是完全可行的。例如,我们可以更新我们的天气预报应用程序,以显示更多的选择,具体取决于温度:

        +

        将另一个 if ... else 语句放在另一个中 - 嵌套它是完全可行的。例如,我们可以更新我们的天气预报应用程序,以显示更多的选择,具体取决于温度:

        if (choice === 'sunny') {
           if (temperature < 86) {
        @@ -190,19 +190,19 @@ 

        嵌套if ... else

        } }
        -

        即使代码全部一起工作,每个if ... else语句完全独立于另一个。

        +

        即使代码全部一起工作,每个 if ... else 语句完全独立于另一个。

        逻辑运算符:&&  , || 和 !

        -

        如果要测试多个条件,而不需要编写嵌套if ... else语句,逻辑运算符可以帮助您。当在条件下使用时,前两个执行以下操作:

        +

        如果要测试多个条件,而不需要编写嵌套 if ... else 语句,逻辑运算符可以帮助您。当在条件下使用时,前两个执行以下操作:

        • && — 逻辑与; 使得并列两个或者更多的表达式成为可能,只有当这些表达式每一个都返回true时,整个表达式才会返回true.
        • || — 逻辑或; 当两个或者更多表达式当中的任何一个返回 true 则整个表达式将会返回 true.
        • -
        • !  — 逻辑非; 对一个布尔值取反, 非true返回false,非false返回true.
        • +
        • !  — 逻辑非; 对一个布尔值取反,非 true 返回 false,非 false 返回 true.
        -

        举一个逻辑 && 的例子, 刚才的那段代码片段可以写成下面这样:

        +

        举一个逻辑 && 的例子,刚才的那段代码片段可以写成下面这样:

        if (choice === 'sunny' && temperature < 86) {
           para.textContent = 'It is ' + temperature + ' degrees outside — nice and sunny. Let\'s go out to the beach, or the park, and get an ice cream.';
        @@ -220,7 +220,7 @@ 

        逻辑运算符:&&  , || 和 !

        -

        最后一种类型的逻辑运算符,  逻辑非!  运算符表示, 可以用于对一个表达式取否. 让我们把  非运算符 结合上一个例子里的  或表达式 看看:

        +

        最后一种类型的逻辑运算符,  逻辑非!  运算符表示,可以用于对一个表达式取否。让我们把  非运算符 结合上一个例子里的  或表达式 看看:

        if (!(iceCreamVanOutside || houseStatus === 'on fire')) {
           console.log('Probably should just stay in then.');
        @@ -230,29 +230,29 @@ 

        逻辑运算符:&&  , || 和 !

        在这一段代码中,如果逻辑或所在的语句返回 true,则非运算符会将其取否,于是整个表达式的返回值将会是false

        -

        您可以在任何结构中随意合并很多个逻辑表达式。接下来的例子将会只在或运算符两边的语句同时返回true时才会执行代码,这也就意味着整个与运算符语句将会返回true:

        +

        您可以在任何结构中随意合并很多个逻辑表达式。接下来的例子将会只在或运算符两边的语句同时返回 true 时才会执行代码,这也就意味着整个与运算符语句将会返回 true:

        if ((x === 5 || y > 3 || z <= 10) && (loggedIn || userName === 'Steve')) {
           // run the code
         }
        -

        在条件语句中运用或逻辑运算符最常见的错误是尝试声明变量后,仅检查该变量一次的情况下赋予很多个都会返回true的值,不同的值之间用 || (或)运算符分隔。比如:

        +

        在条件语句中运用或逻辑运算符最常见的错误是尝试声明变量后,仅检查该变量一次的情况下赋予很多个都会返回 true 的值,不同的值之间用 || (或) 运算符分隔。比如:

        if (x === 5 || 7 || 10 || 20) {
           // run my code
         }
        -

        在这个例子里 if(...) 里的条件总为真,因为 7 (或者其它非零的数) 的值总是为真. 这个条件实际意思是 "如果x等于5, 或者7为真 — 它总是成立的". 这不是我们想要的逻辑,为了 让它正常工作你必须指定每个或表达式两边都是完整的检查:

        +

        在这个例子里 if(...) 里的条件总为真,因为 7 (或者其它非零的数) 的值总是为真。这个条件实际意思是 "如果 x 等于 5, 或者 7 为真 — 它总是成立的". 这不是我们想要的逻辑,为了 让它正常工作你必须指定每个或表达式两边都是完整的检查:

        if (x === 5 || x === 7 || x === 10 ||x === 20) {
           // run my code
         }
        -

        switch语句

        +

        switch 语句

        -

        if...else 语句能够很好地实现条件代码,但是它们不是没有缺点。 它们主要适用于您只有几个选择的情况,每个都需要相当数量的代码来运行,和/或 的条件很复杂的情况(例如多个逻辑运算符)。 对于只想将变量设置一系列为特定值的选项或根据条件打印特定语句的情况,语法可能会很麻烦,特别是如果您有大量选择。

        +

        if...else 语句能够很好地实现条件代码,但是它们不是没有缺点。它们主要适用于您只有几个选择的情况,每个都需要相当数量的代码来运行,和/或 的条件很复杂的情况(例如多个逻辑运算符)。对于只想将变量设置一系列为特定值的选项或根据条件打印特定语句的情况,语法可能会很麻烦,特别是如果您有大量选择。

        -

        switch 语句在这里是您的朋友 - 他们以单个表达式/值作为输入,然后查看多个选项,直到找到与该值相匹配的选项,执行与之相关的代码。 这里有一些伪代码,可以给你一点灵感:

        +

        switch 语句在这里是您的朋友 - 他们以单个表达式/值作为输入,然后查看多个选项,直到找到与该值相匹配的选项,执行与之相关的代码。这里有一些伪代码,可以给你一点灵感:

        switch (expression) {
           case choice1:
        @@ -269,25 +269,25 @@ 

        switch语句

        actually, just run this code }
        -

        这里我们得到:

        +

        这里我们得到:

          -
        1. 关键字 switch, 后跟一组括号.
        2. -
        3. 括号内的表达式或值.
        4. +
        5. 关键字 switch, 后跟一组括号。
        6. +
        7. 括号内的表达式或值。
        8. 关键字 case, 后跟一个选项的表达式/值,后面跟一个冒号.
        9. -
        10. 如果选择与表达式匹配,则运行一些代码.
        11. -
        12. 一个 break 语句, 分号结尾. 如果先前的选择与表达式/值匹配,则浏览器在此停止执行代码块,并执行switch语句之后的代码.
        13. -
        14. 你可以添加任意的 case 选项(选项3-5).
        15. -
        16. 关键字 default, 后面跟随和 case 完全相同的代码模式 (选项 3–5), except that default 之后不需要再有选项, 并且您不需要 break 语句, 因为之后没有任何运行代码. 如果之前没有选项匹配,则运行default选项.
        17. +
        18. 如果选择与表达式匹配,则运行一些代码。
        19. +
        20. 一个 break 语句,分号结尾。如果先前的选择与表达式/值匹配,则浏览器在此停止执行代码块,并执行switch语句之后的代码.
        21. +
        22. 你可以添加任意的 case 选项(选项 3-5).
        23. +
        24. 关键字 default, 后面跟随和 case 完全相同的代码模式 (选项 3–5), except that default 之后不需要再有选项, 并且您不需要 break 语句, 因为之后没有任何运行代码. 如果之前没有选项匹配,则运行default选项。
        -

        Note: default 部分不是必须的 - 如果表达式不可能存在未知值,则可以安全地省略它。 如果有机会,您需要包括它来处理未知的情况。

        +

        Note: default 部分不是必须的 - 如果表达式不可能存在未知值,则可以安全地省略它。如果有机会,您需要包括它来处理未知的情况。

        -

        switch语句示例

        +

        switch 语句示例

        -

        我们来看一个真实的例子 - 我们将重写天气预报应用程序,以改用switch语句:

        +

        我们来看一个真实的例子 - 我们将重写天气预报应用程序,以改用 switch 语句:

        <label for="weather">Select the weather type today: </label>
         <select id="weather">
        @@ -394,7 +394,7 @@ 

        主动学习:一个简单的日

        我们需要你在onchange处理函数中写一个条件语句,就在// ADD CONDITIONAL HERE任务的下面  。这应该:

          -
        1. 查看所选月份(存储在choice变量中,这将是<select>值更改后的元素值,例如“1月”)。
        2. +
        3. 查看所选月份(存储在choice变量中,这将是<select>值更改后的元素值,例如“1 月”)。
        4. 设置一个被调用days为等于所选月份天数的变量。为此,您必须查看一年中每个月的天数。为了这个例子的目的,你可以忽略闰年。
        @@ -516,7 +516,7 @@

        Playable code

        主动学习:更多颜色选择!

        -

        在这个例子中,您将要采取我们前面看到的三元运算符示例,并将三元运算符转换为一个switch语句,这将允许我们对简单的网站应用更多的选择。看看<select>- 这次你会看到它不是两个主题选项,而是五个。您需要在// ADD SWITCH STATEMENT注释下面添加一个switch语句:

        +

        在这个例子中,您将要采取我们前面看到的三元运算符示例,并将三元运算符转换为一个 switch 语句,这将允许我们对简单的网站应用更多的选择。看看<select>- 这次你会看到它不是两个主题选项,而是五个。您需要在// ADD SWITCH STATEMENT注释下面添加一个 switch 语句:

        • 它应该接受choice变量作为其输入表达式。
        • @@ -595,7 +595,7 @@
          Playable code 2

          结论

          -

          这就是现在您真正需要了解的JavaScript中的条件结构!我相信你会理解这些概念,并轻松地通过这些例子; 如果有什么不明白的,请随时阅读文章,或者联系我们寻求帮助。

          +

          这就是现在您真正需要了解的 JavaScript 中的条件结构!我相信你会理解这些概念,并轻松地通过这些例子; 如果有什么不明白的,请随时阅读文章,或者联系我们寻求帮助。

          参见

          diff --git a/files/zh-cn/learn/javascript/building_blocks/events/index.html b/files/zh-cn/learn/javascript/building_blocks/events/index.html index 4e5df75ef7fa6f..ef22cf114921c0 100644 --- a/files/zh-cn/learn/javascript/building_blocks/events/index.html +++ b/files/zh-cn/learn/javascript/building_blocks/events/index.html @@ -19,11 +19,11 @@ - - + + - + @@ -31,11 +31,11 @@

          一系列事件

          -

          就像上面提到的, 事件是您在编程时系统内发生的动作或者发生的事情——系统会在事件出现时产生或触发某种信号,并且会提供一个自动加载某种动作(列如:运行一些代码)的机制,比如在一个机场,当跑道清理完成,飞机可以起飞时,飞行员会收到一个信号,因此他们开始起飞。

          +

          就像上面提到的,事件是您在编程时系统内发生的动作或者发生的事情——系统会在事件出现时产生或触发某种信号,并且会提供一个自动加载某种动作(列如:运行一些代码)的机制,比如在一个机场,当跑道清理完成,飞机可以起飞时,飞行员会收到一个信号,因此他们开始起飞。

          -

          在 Web 中, 事件在浏览器窗口中被触发并且通常被绑定到窗口内部的特定部分 — 可能是一个元素、一系列元素、被加载到这个窗口的 HTML 代码或者是整个浏览器窗口。举几个可能发生的不同事件:

          +

          在 Web 中,事件在浏览器窗口中被触发并且通常被绑定到窗口内部的特定部分 — 可能是一个元素、一系列元素、被加载到这个窗口的 HTML 代码或者是整个浏览器窗口。举几个可能发生的不同事件:

          • 用户在某个元素上点击鼠标或悬停光标。
          • @@ -47,7 +47,7 @@

            一系列事件

          • 发生错误。
          -

          如果您想看看更多其他的事件 ,请移步至MDN的Event reference

          +

          如果您想看看更多其他的事件,请移步至 MDN 的Event reference

          每个可用的事件都会有一个事件处理器,也就是事件触发时会运行的代码块。当我们定义了一个用来回应事件被激发的代码块的时候,我们说我们注册了一个事件处理器。注意事件处理器有时候被叫做事件监听器——从我们的用意来看这两个名字是相同的,尽管严格地来说这块代码既监听也处理事件。监听器留意事件是否发生,然后处理器就是对事件发生做出的回应。

          @@ -65,7 +65,7 @@

          一个简单的例子

          button { margin: 10px };
          -

          JavaScript代码如下所示:

          +

          JavaScript 代码如下所示:

          const btn = document.querySelector('button');
           
          @@ -90,7 +90,7 @@ 

          这不仅应用在网页上

          值得注意的是并不是只有 JavaScript 使用事件——大多的编程语言都有这种机制,并且它们的工作方式不同于 JavaScript。实际上,JavaScript 网页上的事件机制不同于在其他环境中的事件机制。

          -

          比如, Node.js 是一种非常流行的允许开发者使用 JavaScript 来建造网络和服务器端应用的运行环境。Node.js event model 依赖定期监听事件的监听器和定期处理事件的处理器——虽然听起来好像差不多,但是实现两者的代码是非常不同的,Node.js 使用像 on ( ) 这样的函数来注册一个事件监听器,使用 once ( ) 这样函数来注册一个在运行一次之后注销的监听器。 HTTP connect event docs 提供了很多例子。

          +

          比如,Node.js 是一种非常流行的允许开发者使用 JavaScript 来建造网络和服务器端应用的运行环境。Node.js event model 依赖定期监听事件的监听器和定期处理事件的处理器——虽然听起来好像差不多,但是实现两者的代码是非常不同的,Node.js 使用像 on ( ) 这样的函数来注册一个事件监听器,使用 once ( ) 这样函数来注册一个在运行一次之后注销的监听器。 HTTP connect event docs 提供了很多例子。

          另外一个例子:您可以使用 JavaScript 来开发跨浏览器的插件(使用 WebExtensions 开发技术。事件模型和网站的事件模型是相似的,仅有一点点不同——事件监听属性是大驼峰的(如onMessage而不是onmessage),还需要与 addListener 函数结合, 参见 runtime.onMessage page 上的一个例子。

          @@ -129,17 +129,17 @@

          事件处理器属性

          首先将 random-color-eventhandlerproperty.html 复制到本地,然后用浏览器打开。别慌,这只是我们之前已经进行过的一个简单随机颜色的示例的代码复制。将 btn.onclick 依次换成其他值,在浏览器中观察效果。

            -
          • btn.onfocusbtn.onblur — 颜色将于按钮被置于焦点或解除焦点时改变(尝试使用Tab移动至按钮上,然后再移开)。这些通常用于显示有关如何在置于焦点时填写表单字段的信息,或者如果表单字段刚刚填入不正确的值,则显示错误消息。
          • +
          • btn.onfocusbtn.onblur — 颜色将于按钮被置于焦点或解除焦点时改变(尝试使用 Tab 移动至按钮上,然后再移开)。这些通常用于显示有关如何在置于焦点时填写表单字段的信息,或者如果表单字段刚刚填入不正确的值,则显示错误消息。
          • btn.ondblclick — 颜色将仅于按钮被双击时改变。
          • -
          • window.onkeypress, window.onkeydown, window.onkeyup — 当按钮被按下时颜色会发生改变. keypress 指的是通俗意义上的按下按钮 (按下并松开), 而 keydown 和 keyup 指的是按键动作的一部分,分别指按下和松开. 注意如果你将事件处理器添加到按钮本身,它将不会工作 — 我们只能将它添加到代表整个浏览器窗口的 window对象中。
          • -
          • btn.onmouseover 和 btn.onmouseout — 颜色将会在鼠标移入按钮上方时发生改变, 或者当它从按钮移出时.
          • +
          • window.onkeypress, window.onkeydown, window.onkeyup — 当按钮被按下时颜色会发生改变。keypress 指的是通俗意义上的按下按钮 (按下并松开), 而 keydown 和 keyup 指的是按键动作的一部分,分别指按下和松开。注意如果你将事件处理器添加到按钮本身,它将不会工作 — 我们只能将它添加到代表整个浏览器窗口的 window对象中。
          • +
          • btn.onmouseover 和 btn.onmouseout — 颜色将会在鼠标移入按钮上方时发生改变,或者当它从按钮移出时。

          一些事件非常通用,几乎在任何地方都可以用(比如 onclick 几乎可以用在几乎每一个元素上),然而另一些元素就只能在特定场景下使用,比如我们只能在 video 元素上使用 onplay 。

          行内事件处理器 - 请勿使用

          -

          你也许在你的代码中看到过这么一种写法:

          +

          你也许在你的代码中看到过这么一种写法:

          <button onclick="bgChange()">Press me</button>
           
          @@ -150,18 +150,18 @@

          行内事件处理器 - 请勿使 }

          -

          Note: 您可以在GitHub上找到这个示例的完整源代码(也可以在线运行).

          +

          Note: 您可以在GitHub上找到这个示例的完整源代码 (也可以在线运行).

          -

          在Web上注册事件处理程序的最早方法是类似于上面所示的事件处理程序HTML属性(也称为内联事件处理程序)—属性值实际上是当事件发生时要运行的JavaScript代码。上面的例子中调用一个在{{htmlelement("script")}}元素在同一个页面上,但也可以直接在属性内插入JavaScript,例如:

          +

          在 Web 上注册事件处理程序的最早方法是类似于上面所示的事件处理程序 HTML 属性(也称为内联事件处理程序)—属性值实际上是当事件发生时要运行的 JavaScript 代码。上面的例子中调用一个在{{htmlelement("script")}}元素在同一个页面上,但也可以直接在属性内插入 JavaScript,例如:

          <button onclick="alert('Hello, this is my old-fashioned event handler!');">Press me</button>
          -

          你会发现HTML属性等价于对许多事件处理程序的属性;但是,你不应该使用这些 —— 他们被认为是不好的做法。使用一个事件处理属性似乎看起来很简单,如果你只是在做一些非常快的事情,但很快就变得难以管理和效率低下。

          +

          你会发现 HTML 属性等价于对许多事件处理程序的属性;但是,你不应该使用这些 —— 他们被认为是不好的做法。使用一个事件处理属性似乎看起来很简单,如果你只是在做一些非常快的事情,但很快就变得难以管理和效率低下。

          一开始,您不应该混用 HTML 和 JavaScript,因为这样文档很难解析——最好的办法是只在一块地方写 JavaScript 代码。

          -

          即使在单一文件中,内置事件处理器也不是一个好主意。一个按钮看起来还好,但是如果有一百个按钮呢?您得在文件中加上100个属性。这很快就会成为维护人员的噩梦。使用 Java Script,您可以给网页中的 button 都加上事件处理器。就像下面这样:

          +

          即使在单一文件中,内置事件处理器也不是一个好主意。一个按钮看起来还好,但是如果有一百个按钮呢?您得在文件中加上 100 个属性。这很快就会成为维护人员的噩梦。使用 Java Script,您可以给网页中的 button 都加上事件处理器。就像下面这样:

          const buttons = document.querySelectorAll('button');
           
          @@ -173,7 +173,7 @@ 

          行内事件处理器 - 请勿使

          注释: 将您的编程逻辑与内容分离也会让您的站点对搜索引擎更加友好。

          -

          addEventListener() 和removeEventListener()

          +

          addEventListener() 和 removeEventListener()

          新的事件触发机制被定义在 Document Object Model (DOM) Level 2 Events Specification, 这个细则给浏览器提供了一个函数 — addEventListener()。这个函数和事件处理属性是类似的,但是语法略有不同。我们可以重写上面的随机颜色背景代码:

          @@ -187,10 +187,10 @@

          addEventListener() 和removeEve btn.addEventListener('click', bgChange);

          -

          注释: 您可以在Github上找到这个示例的完整源代码(也可以 在线运行)。

          +

          注释: 您可以在Github上找到这个示例的完整源代码 (也可以 在线运行)。

          -

          在addEventListener() 函数中, 我们具体化了两个参数——我们想要将处理器应用上去的事件名称,和包含我们用来回应事件的函数的代码。注意将这些代码全部放到一个匿名函数中是可行的:

          +

          在addEventListener() 函数中,我们具体化了两个参数——我们想要将处理器应用上去的事件名称,和包含我们用来回应事件的函数的代码。注意将这些代码全部放到一个匿名函数中是可行的:

          btn.addEventListener('click', function() {
             var rndCol = 'rgb(' + random(255) + ',' + random(255) + ',' + random(255) + ')';
          @@ -220,13 +220,13 @@ 

          addEventListener() 和removeEve

          我该使用哪种机制?

          -

          在三种机制中,您绝对不应该使用HTML事件处理程序属性 - 这些属性已经过时了,而且也是不好的做法,如上所述.

          +

          在三种机制中,您绝对不应该使用 HTML 事件处理程序属性 - 这些属性已经过时了,而且也是不好的做法,如上所述。

          -

          另外两种是相对可互换的,至少对于简单的用途:

          +

          另外两种是相对可互换的,至少对于简单的用途:

            -
          • 事件处理程序属性功能和选项会更少,但是具有更好的跨浏览器兼容性(在Internet Explorer 8的支持下),您应该从这些开始学起。
          • -
          • DOM Level 2 Events (addEventListener(), etc.) 更强大,但也可以变得更加复杂,并且支持不足(只支持到Internet Explorer 9)。 但是您也应该尝试这个方法,并尽可能地使用它们。
          • +
          • 事件处理程序属性功能和选项会更少,但是具有更好的跨浏览器兼容性 (在 Internet Explorer 8 的支持下),您应该从这些开始学起。
          • +
          • DOM Level 2 Events (addEventListener(), etc.) 更强大,但也可以变得更加复杂,并且支持不足(只支持到 Internet Explorer 9)。但是您也应该尝试这个方法,并尽可能地使用它们。

          第三种机制(DOM Level 2 Events (addEventListener(), etc.))的主要优点是,如果需要的话,可以使用removeEventListener()删除事件处理程序代码,而且如果有需要,您可以向同一类型的元素添加多个监听器。例如,您可以在一个元素上多次调用addEventListener('click', function() { ... }),并可在第二个参数中指定不同的函数。对于事件处理程序属性来说,这是不可能的,因为后面任何设置的属性都会尝试覆盖较早的属性,例如:

          @@ -236,7 +236,7 @@

          我该使用哪种机制?

          etc.
          -

          注解:如果您在工作中被要求支持比Internet Explorer 8更老的浏览器,那么您可能会遇到困难,因为这些古老的浏览器会使用与现代浏览器不同的事件处理模型。但是不要害怕,大多数 JavaScript 库(例如 jQuery )都内置了能够跨浏览器差异的函数。在你学习 JavaScript 旅程里的这个阶段,不要太担心这个问题。

          +

          注解:如果您在工作中被要求支持比 Internet Explorer 8 更老的浏览器,那么您可能会遇到困难,因为这些古老的浏览器会使用与现代浏览器不同的事件处理模型。但是不要害怕,大多数 JavaScript 库 (例如 jQuery ) 都内置了能够跨浏览器差异的函数。在你学习 JavaScript 旅程里的这个阶段,不要太担心这个问题。

          其他事件概念

          @@ -245,7 +245,7 @@

          其他事件概念

          事件对象

          -

          有时候在事件处理函数内部,您可能会看到一个固定指定名称的参数,例如eventevt或简单的e。 这被称为事件对象,它被自动传递给事件处理函数,以提供额外的功能和信息。 例如,让我们稍稍重写一遍我们的随机颜色示例:

          +

          有时候在事件处理函数内部,您可能会看到一个固定指定名称的参数,例如eventevt或简单的e。这被称为事件对象,它被自动传递给事件处理函数,以提供额外的功能和信息。例如,让我们稍稍重写一遍我们的随机颜色示例:

          function bgChange(e) {
             const rndCol = 'rgb(' + random(255) + ',' + random(255) + ',' + random(255) + ')';
          @@ -256,16 +256,16 @@ 

          事件对象

          btn.addEventListener('click', bgChange);
          -

          Note: 您可以在Github上查看这个示例的 完整代码 ,或者在这里查看 实时演示

          +

          Note: 您可以在 Github 上查看这个示例的 完整代码 ,或者在这里查看 实时演示

          -

          在这里,您可以看到我们在函数中包括一个事件对象e,并在函数中设置背景颜色样式在e.target上 - 它指的是按钮本身。 事件对象 etarget属性始终是事件刚刚发生的元素的引用。 所以在这个例子中,我们在按钮上设置一个随机的背景颜色,而不是页面。

          +

          在这里,您可以看到我们在函数中包括一个事件对象e,并在函数中设置背景颜色样式在e.target上 - 它指的是按钮本身。事件对象 etarget属性始终是事件刚刚发生的元素的引用。所以在这个例子中,我们在按钮上设置一个随机的背景颜色,而不是页面。

          -

          Note: 您可以使用任何您喜欢的名称作为事件对象 - 您只需要选择一个名称,然后可以在事件处理函数中引用它。 开发人员最常使用 e / evt / event,因为它们很简单易记。 坚持标准总是很好。

          +

          Note: 您可以使用任何您喜欢的名称作为事件对象 - 您只需要选择一个名称,然后可以在事件处理函数中引用它。开发人员最常使用 e / evt / event,因为它们很简单易记。坚持标准总是很好。

          -

          当您要在多个元素上设置相同的事件处理程序时,e.target非常有用,并且在发生事件时对所有元素执行某些操作.  例如,你可能有一组16块方格,当它们被点击时就会消失。用e.target总是能准确选择当前操作的东西(方格)并执行操作让它消失,而不是必须以更困难的方式选择它。在下面的示例中(请参见useful-eventtarget.html完整代码;也可以在线运行running live)我们使用JavaScript创建了16个<div>元素。接着我们使用 document.querySelectorAll()选择全部的元素,然后遍历每一个,为每一个元素都添加一个onclick单击事件,每当它们点击时就会为背景添加一个随机颜色。

          +

          当您要在多个元素上设置相同的事件处理程序时,e.target非常有用,并且在发生事件时对所有元素执行某些操作。 例如,你可能有一组 16 块方格,当它们被点击时就会消失。用 e.target 总是能准确选择当前操作的东西(方格)并执行操作让它消失,而不是必须以更困难的方式选择它。在下面的示例中 (请参见useful-eventtarget.html完整代码;也可以在线运行running live)我们使用 JavaScript 创建了 16 个<div>元素。接着我们使用 document.querySelectorAll()选择全部的元素,然后遍历每一个,为每一个元素都添加一个onclick单击事件,每当它们点击时就会为背景添加一个随机颜色。

          const divs = document.querySelectorAll('div');
           
          @@ -275,7 +275,7 @@ 

          事件对象

          } }
          -

          输出如下(试着点击它-玩的开心):

          +

          输出如下 (试着点击它 - 玩的开心):

          -

          这里我们用一个onsubmit事件处理程序(在提交的时候,在一个表单上发起submit事件)来实现一个非常简单的检查,用于测试文本字段是否为空。 如果是,我们在事件对象上调用preventDefault()函数,这样就停止了表单提交,然后在我们表单下面的段落中显示一条错误消息,告诉用户什么是错误的:

          +

          这里我们用一个onsubmit事件处理程序(在提交的时候,在一个表单上发起submit事件)来实现一个非常简单的检查,用于测试文本字段是否为空。如果是,我们在事件对象上调用preventDefault()函数,这样就停止了表单提交,然后在我们表单下面的段落中显示一条错误消息,告诉用户什么是错误的:

          const form = document.querySelector('form');
           const fname = document.getElementById('fname');
          @@ -371,7 +371,7 @@ 

          阻止默认行为

          } }
          -

          显然,这是一种非常弱的表单验证——例如,用户输入空格或数字提交表单,表单验证并不会阻止用户提交——这不是我们例子想要达到的目的。输出如下:

          +

          显然,这是一种非常弱的表单验证——例如,用户输入空格或数字提交表单,表单验证并不会阻止用户提交——这不是我们例子想要达到的目的。输出如下:

          {{ EmbedLiveSample('Preventing_default_behaviour', '100%', 140) }}

          @@ -473,13 +473,13 @@
          Hidden video example
          </video> </div> -

          当‘’button‘’元素按钮被单击时,将显示视频,它是通过将改变<div>的class属性值从hidden变为showing(这个例子的CSS包含两个class,它们分别控制这个<div>盒子在屏幕上显示还是隐藏。):

          +

          当‘’button‘’元素按钮被单击时,将显示视频,它是通过将改变<div>的class 属性值从hidden变为showing(这个例子的 CSS 包含两个class,它们分别控制这个<div>盒子在屏幕上显示还是隐藏。):

          btn.onclick = function() {
             videoBox.setAttribute('class', 'showing');
           }
          -

          然后我们再添加几个onclick事件处理器,第一个添加在<div>元素上,第二个添加在<video>元素上。这个想法是当视频(<video>)外 <div>元素内这块区域被单击时,这个视频盒子应该再次隐藏;当单击视频(<video>)本身,这个视频将开始播放。

          +

          然后我们再添加几个onclick事件处理器,第一个添加在<div>元素上,第二个添加在<video>元素上。这个想法是当视频 (<video>)外 <div>元素内这块区域被单击时,这个视频盒子应该再次隐藏;当单击视频 (<video>)本身,这个视频将开始播放。

          videoBox.onclick = function() {
             videoBox.setAttribute('class', 'hidden');
          @@ -489,18 +489,18 @@ 
          Hidden video example
          video.play(); };
          -

          但是有一个问题 - 当您点击video开始播放的视频时,它会在同一时间导致<div>也被隐藏。 这是因为video<div>之内 - video<div>的一个子元素 - 所以点击video实际上是同时也运行<div>上的事件处理程序。

          +

          但是有一个问题 - 当您点击video开始播放的视频时,它会在同一时间导致<div>也被隐藏。这是因为video<div>之内 - video<div>的一个子元素 - 所以点击video实际上是同时也运行<div>上的事件处理程序。

          对事件冒泡和捕捉的解释

          -

          当一个事件发生在具有父元素的元素上(例如,在我们的例子中是<video>元素)时,现代浏览器运行两个不同的阶段 - 捕获阶段和冒泡阶段。 在捕获阶段:

          +

          当一个事件发生在具有父元素的元素上 (例如,在我们的例子中是<video>元素) 时,现代浏览器运行两个不同的阶段 - 捕获阶段和冒泡阶段。在捕获阶段:

          • 浏览器检查元素的最外层祖先<html>,是否在捕获阶段中注册了一个onclick事件处理程序,如果是,则运行它。
          • 然后,它移动到<html>中单击元素的下一个祖先元素,并执行相同的操作,然后是单击元素再下一个祖先元素,依此类推,直到到达实际点击的元素。
          -

          在冒泡阶段,恰恰相反:

          +

          在冒泡阶段,恰恰相反:

          • 浏览器检查实际点击的元素是否在冒泡阶段中注册了一个onclick事件处理程序,如果是,则运行它
          • @@ -520,7 +520,7 @@

            对事件冒泡和捕捉的解释

            用 stopPropagation() 修复问题 -

            这是令人讨厌的行为,但有一种方法来解决它!标准事件对象具有可用的名为 stopPropagation()的函数, 当在事件对象上调用该函数时,它只会让当前事件处理程序运行,但事件不会在冒泡链上进一步扩大,因此将不会有更多事件处理器被运行(不会向上冒泡)。所以,我们可以通过改变前面代码块中的第二个处理函数来解决当前的问题:

            +

            这是令人讨厌的行为,但有一种方法来解决它!标准事件对象具有可用的名为 stopPropagation()的函数,当在事件对象上调用该函数时,它只会让当前事件处理程序运行,但事件不会在冒泡链上进一步扩大,因此将不会有更多事件处理器被运行 (不会向上冒泡)。所以,我们可以通过改变前面代码块中的第二个处理函数来解决当前的问题:

            video.onclick = function(e) {
               e.stopPropagation();
            @@ -530,26 +530,26 @@ 

            用 stopPropagation() 修复问题

            你可以尝试把 show-video-box.html source code 拷贝到本地,然后自己动手修复它,或者在 show-video-box-fixed.html 页面查看修复结果(也可以在这里 source code 查看源码)。

            -

            注解: 为什么我们要弄清楚捕捉和冒泡呢?那是因为,在过去糟糕的日子里,浏览器的兼容性比现在要小得多,Netscape(网景)只使用事件捕获,而Internet Explorer只使用事件冒泡。当W3C决定尝试规范这些行为并达成共识时,他们最终得到了包括这两种情况(捕捉和冒泡)的系统,最终被应用在现在浏览器里。

            +

            注解: 为什么我们要弄清楚捕捉和冒泡呢?那是因为,在过去糟糕的日子里,浏览器的兼容性比现在要小得多,Netscape(网景)只使用事件捕获,而 Internet Explorer 只使用事件冒泡。当 W3C 决定尝试规范这些行为并达成共识时,他们最终得到了包括这两种情况(捕捉和冒泡)的系统,最终被应用在现在浏览器里。

            -

            注解: 如上所述,默认情况下,所有事件处理程序都是在冒泡阶段注册的,这在大多数情况下更有意义。如果您真的想在捕获阶段注册一个事件,那么您可以通过使用addEventListener()注册您的处理程序,并将可选的第三个属性设置为true。

            +

            注解: 如上所述,默认情况下,所有事件处理程序都是在冒泡阶段注册的,这在大多数情况下更有意义。如果您真的想在捕获阶段注册一个事件,那么您可以通过使用addEventListener()注册您的处理程序,并将可选的第三个属性设置为 true。

            事件委托

            -

            冒泡还允许我们利用事件委托——这个概念依赖于这样一个事实,如果你想要在大量子元素中单击任何一个都可以运行一段代码,您可以将事件监听器设置在其父节点上,并让子节点上发生的事件冒泡到父节点上,而不是每个子节点单独设置事件监听器。

            +

            冒泡还允许我们利用事件委托——这个概念依赖于这样一个事实,如果你想要在大量子元素中单击任何一个都可以运行一段代码,您可以将事件监听器设置在其父节点上,并让子节点上发生的事件冒泡到父节点上,而不是每个子节点单独设置事件监听器。

            一个很好的例子是一系列列表项,如果你想让每个列表项被点击时弹出一条信息,您可以将click单击事件监听器设置在父元素<ul>上,这样事件就会从列表项冒泡到其父元素<ul>上。

            -

            这个的概念在David Walsh的博客上有更多的解释,并有多个例子——看看How JavaScript Event Delegation Works.

            +

            这个的概念在 David Walsh 的博客上有更多的解释,并有多个例子——看看How JavaScript Event Delegation Works.

            结论

            -

            现在您应该知道在这个早期阶段您需要了解的所有web事件。如上所述,事件并不是JavaScript的核心部分——它们是在浏览器Web APIs中定义的。

            +

            现在您应该知道在这个早期阶段您需要了解的所有 web 事件。如上所述,事件并不是 JavaScript 的核心部分——它们是在浏览器 Web APIs 中定义的。

            -

            另外,理解JavaScript在不同环境下使用不同的事件模型很重要——从Web api到其他领域,如浏览器WebExtensions和Node.js(服务器端JavaScript)。我们并不期望您现在了解所有这些领域,但是当您在学习web开发的过程中,理解这些事件的基础是很有帮助的。

            +

            另外,理解 JavaScript 在不同环境下使用不同的事件模型很重要——从 Web api 到其他领域,如浏览器 WebExtensions 和 Node.js(服务器端 JavaScript)。我们并不期望您现在了解所有这些领域,但是当您在学习 web 开发的过程中,理解这些事件的基础是很有帮助的。

            如果你有什么不明白的地方,请重新阅读这篇文章,或者联系contact us我们寻求帮助。

            diff --git a/files/zh-cn/learn/javascript/building_blocks/functions/index.html b/files/zh-cn/learn/javascript/building_blocks/functions/index.html index a222ebd7dd5eab..b139eb1995b505 100644 --- a/files/zh-cn/learn/javascript/building_blocks/functions/index.html +++ b/files/zh-cn/learn/javascript/building_blocks/functions/index.html @@ -1,5 +1,5 @@ --- -title: 函数-可复用代码块 +title: 函数 - 可复用代码块 slug: learn/JavaScript/Building_blocks/Functions tags: - API @@ -18,26 +18,26 @@
            {{PreviousMenuNext("Learn/JavaScript/Building_blocks/Looping_code","Learn/JavaScript/Building_blocks/Build_your_own_function", "Learn/JavaScript/Building_blocks")}}
            -

            在JavaScript中另一个基本概念是函数, 它允许你在一个代码块中存储一段用于处理单任务的代码,然后在任何你需要的时候用一个简短的命令来调用,而不是把相同的代码写很多次。在本文中,我们将探索函数的基本概念,如基本语法、如何定义和调用、范围和参数。

            +

            在 JavaScript 中另一个基本概念是函数, 它允许你在一个代码块中存储一段用于处理单任务的代码,然后在任何你需要的时候用一个简短的命令来调用,而不是把相同的代码写很多次。在本文中,我们将探索函数的基本概念,如基本语法、如何定义和调用、范围和参数。

          前提:基本电脑知识, 对HTML和CSS的基本了解,及 JavaScript first steps.前提:基本电脑知识,对 HTML 和 CSS 的基本了解,及 JavaScript first steps.
          目标:目标: 了解事件的基本理论,它们怎么在浏览器上运行的,以及在不同的编程环境下事件有何不同。
          - - + + - +
          前提条件:基本的电脑知识,对HTML与CSS有基本的了解,及已阅读: JavaScript first steps(JS的入门)。前提条件:基本的电脑知识,对 HTML 与 CSS 有基本的了解,及已阅读: JavaScript first steps(JS 的入门)。
          目标:目标: 了解 Javascript 函数背后的基本概念。
          -

          我能在哪找到函数?

          +

          我能在哪找到函数?

          -

          在 JavaScript中, 你将发现函数无处不在 。事实上, 到目前为止,我们一直在使用函数,只是我们还没很好的讨论它们。然而现在是时候了,让我们开始聊聊函数,并探索它们的语法。

          +

          在 JavaScript 中,你将发现函数无处不在。事实上,到目前为止,我们一直在使用函数,只是我们还没很好的讨论它们。然而现在是时候了,让我们开始聊聊函数,并探索它们的语法。

          -

          几乎任何时候,只要你使用一个带有一对圆括号()的JavaScript结构,并且你不是在使用一个常见的比如for for循环,while或do…while循环,或者if语句这样的内置语言结构时,那么您就正在使用函数。

          +

          几乎任何时候,只要你使用一个带有一对圆括号()的 JavaScript 结构,并且你不是在使用一个常见的比如 for for 循环,while 或 do…while 循环,或者 if 语句这样的内置语言结构时,那么您就正在使用函数。

          @@ -74,13 +74,13 @@

          浏览器内置函数

          提示:如果需要,你可以随意将这些代码输入浏览器控制台以便于你熟悉其功能。

    -

    JavaScript有许多内置的函数,可以让您做很多有用的事情,而无需自己编写所有的代码。事实上, 许多你调用(运行或者执行的专业词语)浏览器内置函数时调用的代码并不是使用JavaScript来编写——大多数调用浏览器后台的函数的代码,是使用像C++这样更低级的系统语言编写的,而不是像JavaScript这样的web编程语言。

    +

    JavaScript 有许多内置的函数,可以让您做很多有用的事情,而无需自己编写所有的代码。事实上,许多你调用(运行或者执行的专业词语)浏览器内置函数时调用的代码并不是使用 JavaScript 来编写——大多数调用浏览器后台的函数的代码,是使用像 C++这样更低级的系统语言编写的,而不是像 JavaScript 这样的 web 编程语言。

    -

    请记住,这些内置浏览器函数不是核心JavaScript语言的一部分——被定义为浏览器API的一部分,它建立在默认语言之上,以提供更多的功能(请参阅本课程的早期部分以获得更多的描述)。我们将在以后的模块中更详细地使用浏览器API。

    +

    请记住,这些内置浏览器函数不是核心 JavaScript 语言的一部分——被定义为浏览器 API 的一部分,它建立在默认语言之上,以提供更多的功能(请参阅本课程的早期部分以获得更多的描述)。我们将在以后的模块中更详细地使用浏览器 API。

    函数与方法

    -

    程序员把函数称为对象方法(method)的一部分。你还不必了解JavaScript中已建构的对象在更深层次上是如何运作的——你可以等到下一小节,我们会教给你有关对象运作方式的一切。在我们继续前进之前,我们需要澄清一些有关方法和函数概念之间可能存在的误会——当你在网络上浏览相关信息的时候,你很可能会碰上这两个术语。

    +

    程序员把函数称为对象方法(method)的一部分。你还不必了解 JavaScript 中已建构的对象在更深层次上是如何运作的——你可以等到下一小节,我们会教给你有关对象运作方式的一切。在我们继续前进之前,我们需要澄清一些有关方法和函数概念之间可能存在的误会——当你在网络上浏览相关信息的时候,你很可能会碰上这两个术语。

    到目前为止我们所使用的内置代码同属于这两种形式:函数和方法。你可以在这里查看内置函数,内置对象以及其相关方法的完整列表。

    @@ -92,7 +92,7 @@

    函数与方法

    自定义函数

    -

    您在过去的课程中还看到很多定制功能 - 在代码中定义的功能,而不是在浏览器中。每当您看到一个自定义名称后面都带有括号,那么您使用的是自定义函数. 在我们的循环文章中random-canvas-circles.html示例(另见完整的源代码)中,我们包括一个如下所示的自定义函数:draw()

    +

    您在过去的课程中还看到很多定制功能 - 在代码中定义的功能,而不是在浏览器中。每当您看到一个自定义名称后面都带有括号,那么您使用的是自定义函数。在我们的循环文章中random-canvas-circles.html示例(另见完整的源代码)中,我们包括一个如下所示的自定义函数:draw()

    function draw() {
       ctx.clearRect(0,0,WIDTH,HEIGHT);
    @@ -104,7 +104,7 @@ 

    自定义函数

    } }
    -

    该函数在<canvas>元素中绘制100个随机圆。每次我们想要这样做,我们可以使用这个函数来调用这个功能

    +

    该函数在<canvas>元素中绘制 100 个随机圆。每次我们想要这样做,我们可以使用这个函数来调用这个功能

    draw();
    @@ -114,13 +114,13 @@

    自定义函数

    return Math.floor(Math.random()*number); } -

    我们需要这个函数,因为浏览器的内置Math.random()函数只生成一个0到1之间的随机十进制数。我们想要一个0到一个指定数字之间的随机整数。

    +

    我们需要这个函数,因为浏览器的内置Math.random()函数只生成一个 0 到 1 之间的随机十进制数。我们想要一个 0 到一个指定数字之间的随机整数。

    调用函数

    -

    现在你可能很清楚这一点,但仅仅为了防止……,要在函数定义之后,实际使用它,你必须运行或调用它。这是通过将函数名包含在代码的某个地方,后跟圆括号来完成的。

    +

    现在你可能很清楚这一点,但仅仅为了防止……,要在函数定义之后,实际使用它,你必须运行或调用它。这是通过将函数名包含在代码的某个地方,后跟圆括号来完成的。

    function myFunction() {
       alert('hello');
    @@ -143,7 +143,7 @@ 

    匿名函数

    alert('hello'); }
    -

    这个函数叫做匿名函数 — 它没有函数名! 它也不会自己做任何事情。 你通常将匿名函数与事件处理程序一起使用, 例如,如果单击相关按钮,以下操作将在函数内运行代码:

    +

    这个函数叫做匿名函数 — 它没有函数名!它也不会自己做任何事情。你通常将匿名函数与事件处理程序一起使用,例如,如果单击相关按钮,以下操作将在函数内运行代码:

    var myButton = document.querySelector('button');
     
    @@ -200,7 +200,7 @@ 

    函数参数

    Note: 参数有时称为参数(arguments),属性(properties)或甚至属性(attributes)

    -

    例如,浏览器的内置Math.random()函数不需要任何参数。当被调用时,它总是返回0到1之间的随机数:

    +

    例如,浏览器的内置Math.random()函数不需要任何参数。当被调用时,它总是返回 0 到 1 之间的随机数:

    var myNumber = Math.random();
    @@ -227,15 +227,15 @@

    函数参数

    函数作用域和冲突

    -

    我们来谈一谈 {{glossary("scope")}}即作用域 — 处理函数时一个非常重要的概念。当你创建一个函数时,函数内定义的变量和其他东西都在它们自己的单独的范围内, 意味着它们被锁在自己独立的隔间中, 不能被函数外的代码访问。

    +

    我们来谈一谈 {{glossary("scope")}}即作用域 — 处理函数时一个非常重要的概念。当你创建一个函数时,函数内定义的变量和其他东西都在它们自己的单独的范围内,意味着它们被锁在自己独立的隔间中,不能被函数外的代码访问。

    -

    所有函数的最外层被称为全局作用域。 在全局作用域内定义的值可以在任意地方访问。

    +

    所有函数的最外层被称为全局作用域。在全局作用域内定义的值可以在任意地方访问。

    -

    JavaScript由于各种原因而建立,但主要是由于安全性和组织性。有时您不希望变量可以在代码中的任何地方访问 - 您从其他地方调用的外部脚本可能会开始搞乱您的代码并导致问题,因为它们恰好与代码的其他部分使用了相同的变量名称,造成冲突。这可能是恶意的,或者是偶然的。

    +

    JavaScript 由于各种原因而建立,但主要是由于安全性和组织性。有时您不希望变量可以在代码中的任何地方访问 - 您从其他地方调用的外部脚本可能会开始搞乱您的代码并导致问题,因为它们恰好与代码的其他部分使用了相同的变量名称,造成冲突。这可能是恶意的,或者是偶然的。

    -

    例如,假设您有一个HTML文件,它调用两个外部JavaScript文件,并且它们都有一个使用相同名称定义的变量和函数:

    +

    例如,假设您有一个 HTML 文件,它调用两个外部 JavaScript 文件,并且它们都有一个使用相同名称定义的变量和函数:

    <!-- Excerpt from my HTML -->
     <script src="first.js"></script>
    @@ -270,14 +270,14 @@ 

    函数作用域和冲突

    动物园管理员就像全局作用域 - 他或她有钥匙访问每个园子,重新投喂食物,照顾生病的动物等。

    -

    主动学习: 和 scope 玩耍

    +

    主动学习:和 scope 玩耍

    我们来看一个真正的例子来展示范围

    1. 首先,制作我们的function-scope.html示例的本地副本。它包含两个函数a()b(),和三个变量—— xyz——其中两个在函数中被定义,另一个被定义在全局作用域内。它还包含一个名为output()的函数,它接收一个参数,并将其输出到页面的一个段落中。
    2. 在浏览器和文本编辑器中打开示例。
    3. -
    4. 在浏览器开发工具中打开JavaScript控制台。在JavaScript控制台中,输入以下命令:
    5. +
    6. 在浏览器开发工具中打开 JavaScript 控制台。在 JavaScript 控制台中,输入以下命令:
    output(x);
    @@ -289,7 +289,7 @@

    主动学习: 和 scope 玩耍

    output(y);
     output(z);
    -

    这两个都应该返回错误沿“ ReferenceError:y未定义 ”。这是为什么?由于函数作用域 - y和z被锁定在函数a()b()函数中,所以output()从全局作用域调用时无法访问它们。

    +

    这两个都应该返回错误沿“ ReferenceError:y 未定义 ”。这是为什么?由于函数作用域 - y和z被锁定在函数a()b()函数中,所以output()从全局作用域调用时无法访问它们。

            5.但是,从另一个函数里面调用什么呢?尝试编辑a()b()所以他们看起来像这样:

    @@ -303,7 +303,7 @@

    主动学习: 和 scope 玩耍

    output(z); }
    -

    保存代码并重新加载到浏览器中,然后尝试从JavaScript控制台调用a()b()函数:

    +

    保存代码并重新加载到浏览器中,然后尝试从 JavaScript 控制台调用a()b()函数:

    a();
     b();
    @@ -322,12 +322,12 @@

    主动学习: 和 scope 玩耍

    output(x); }
    -

    再次保存并重新加载,并在JavaScript控制台中再次尝试:

    +

    再次保存并重新加载,并在 JavaScript 控制台中再次尝试:

    a();
     b();
    -

    函数 a()b()都应该输出x---1的值。这些没有问题,因为即使output()的调用与x的定义不在同一个作用域内,但x是一个全局变量,所以在所有代码中都可用。

    +

    函数 a()b()都应该输出 x---1 的值。这些没有问题,因为即使output()的调用与x的定义不在同一个作用域内,但x是一个全局变量,所以在所有代码中都可用。

    7.最后,尝试更新您的代码,如下所示:

    @@ -341,7 +341,7 @@

    主动学习: 和 scope 玩耍

    output(y); } -

    再次保存并重新加载,并在JavaScript控制台中再次尝试:

    +

    再次保存并重新加载,并在 JavaScript 控制台中再次尝试:

    a();
     b();
    @@ -384,7 +384,7 @@

    函数内部的函数

    } -

    要确保函数调取的数值处在有效的作用域内。上面的例子中会产生一个错误提示,ReferenceError:myValue is not define,因为尽管myValue变量与函数调用指令处在同一个作用域中, 但它却没有在函数内被定义 —— 实际代码在调用函数时就开始运行了。为了使代码正确运作,你必须将值作为参数传递给函数,如下所示:

    +

    要确保函数调取的数值处在有效的作用域内。上面的例子中会产生一个错误提示,ReferenceError:myValue is not define,因为尽管myValue变量与函数调用指令处在同一个作用域中,但它却没有在函数内被定义 —— 实际代码在调用函数时就开始运行了。为了使代码正确运作,你必须将值作为参数传递给函数,如下所示:

    function myBigFunction() {
       var myValue = 1;
    diff --git a/files/zh-cn/learn/javascript/building_blocks/image_gallery/index.md b/files/zh-cn/learn/javascript/building_blocks/image_gallery/index.md
    index eca5d5951f48a6..9a7c456371bb08 100644
    --- a/files/zh-cn/learn/javascript/building_blocks/image_gallery/index.md
    +++ b/files/zh-cn/learn/javascript/building_blocks/image_gallery/index.md
    @@ -34,7 +34,7 @@ original_slug: learn/JavaScript/Building_blocks/相片走廊
     
     另外,你还可以使用类似 [JSBin](https://jsbin.com/) 或 [Glitch](https://glitch.com/))这些在线编辑器来完成测验。你可以将 HTML、CSS 和 JavaScript 粘贴到这几个在线编辑器中。如果你使用的在线编辑器没有单独的 JavaScript/CSS 面板,请将它们放入 HTML 页面内联的 `