diff options
author | Peter Bengtsson <mail@peterbe.com> | 2020-12-08 14:40:17 -0500 |
---|---|---|
committer | Peter Bengtsson <mail@peterbe.com> | 2020-12-08 14:40:17 -0500 |
commit | 33058f2b292b3a581333bdfb21b8f671898c5060 (patch) | |
tree | 51c3e392513ec574331b2d3f85c394445ea803c6 /files/zh-cn/learn/javascript/building_blocks | |
parent | 8b66d724f7caf0157093fb09cfec8fbd0c6ad50a (diff) | |
download | translated-content-33058f2b292b3a581333bdfb21b8f671898c5060.tar.gz translated-content-33058f2b292b3a581333bdfb21b8f671898c5060.tar.bz2 translated-content-33058f2b292b3a581333bdfb21b8f671898c5060.zip |
initial commit
Diffstat (limited to 'files/zh-cn/learn/javascript/building_blocks')
8 files changed, 3109 insertions, 0 deletions
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 new file mode 100644 index 0000000000..107d68a202 --- /dev/null +++ b/files/zh-cn/learn/javascript/building_blocks/build_your_own_function/index.html @@ -0,0 +1,256 @@ +--- +title: 创建您自己的函数 +slug: learn/JavaScript/Building_blocks/Build_your_own_function +tags: + - JavaScript + - 函数 + - 初学者 + - 学习 + - 教程 +translation_of: Learn/JavaScript/Building_blocks/Build_your_own_function +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/JavaScript/Building_blocks/Functions","Learn/JavaScript/Building_blocks/Return_values", "Learn/JavaScript/Building_blocks")}}</div> + +<p class="summary">我们在之前的文章里大多学的是理论,这篇文章将提供一个练习的机会——您将练习构建一些您自己风格的函数。在练习过程中,我们也会解释一些针对函数的更深层的实用细节。</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">先修知识:</th> + <td>基本的电脑常识,对于HTML和CSS的基本了解, <a href="zh-CN/docs/Learn/JavaScript/First_steps">JavaScript第一步</a>, <a href="zh-CN/docs/Learn/JavaScript/Building_blocks/Functions">函数-可复用代码块</a>。</td> + </tr> + <tr> + <th scope="row">目标:</th> + <td>提供一些练习来构建一个传统的函数,并解释一些有用的相关细节。</td> + </tr> + </tbody> +</table> + +<h2 id="先活跃下气氛:构建一个函数">先活跃下气氛:构建一个函数</h2> + +<p>我们将构建的传统函数将被命名为 <code>displayMessage()</code>,它向用户展示一个传统的消息盒子于web页面的顶部。它充当浏览器内建的 <a href="/zh-CN/docs/Web/API/Window/alert">alert()</a> 函数更有用的替代品。你已经看过了这个,但是我们回复一下我们的记忆——在你的浏览器的 JavaScript控制台中,在任意一个页面里尝试以下代码</p> + +<pre class="brush: js notranslate">alert('This is a message');</pre> + +<p>这个函数只带有一个参数——在 alert box 中展示的字符串。您可以尝试改变字符串来改变消息。</p> + +<p>这个<code>alert()</code>函数不是很好的:您可以<code>alert()</code>出这条信息,但是您不能很容易的表达其他内容,例如颜色,图标或者是其他东西。接下来我们将会构建一个更有趣的函数。</p> + +<div class="note"> +<p><strong>笔记</strong>: 这个例子能够在现代浏览器上很好的工作,但是这个风格在老的浏览器上并没那么有趣。我们建议你实现这个例子时在现代浏览器上,例如Firefox,Opera或者Chrome浏览器。</p> +</div> + +<h2 id="基本函数">基本函数</h2> + +<p>首先,让我们来组织一个基本的函数。</p> + +<div class="note"> +<p><strong>注:</strong>对于函数命名约定,应遵循与<a href="/en-US/Learn/JavaScript/First_steps/Variables#An_aside_on_variable_naming_rules">变量命名约定</a>相同的规则。 这很好,尽你所能理解它们之间的区别 - 函数名称后带有括号,而变量则没有。</p> +</div> + +<ol> + <li>我们希望您首先访问<a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/functions/function-start.html">function-start.html</a>文件并创建一个本地拷贝。您将会看到这个HTML很简单 — 我们的body块仅包含一个按钮。我们还提供了一些基本的CSS来装饰自定义消息框,以及一个用于放置JavaScript代码的{{htmlelement("script")}}元素。</li> + <li>接下来,将下面的代码添加至 <code><script></code> 元素中: + <pre class="brush: js notranslate">function displayMessage() { + +}</pre> + 我们从表示定义一个函数的关键字 <code>function</code>开始,这之后是我们想给我们的函数取的名字;一组括号;和一组大括号。我们要传给我们的函数的任何参数都在括号内,当我们调用该函数时运行的代码均在大括号内。</li> + <li>最后,添加以下代码到大括号中: + <pre class="brush: js notranslate">const html = document.querySelector('html'); + +const panel = document.createElement('div'); +panel.setAttribute('class', 'msgBox'); +html.appendChild(panel); + +const msg = document.createElement('p'); +msg.textContent = 'This is a message box'; +panel.appendChild(msg); + +const closeBtn = document.createElement('button'); +closeBtn.textContent = 'x'; +panel.appendChild(closeBtn); + +closeBtn.onclick = function() { + panel.parentNode.removeChild(panel); +}</pre> + </li> +</ol> + +<p>天哪,这么多代码!好吧,一行一行的解释给你听。</p> + +<p>第一行代码使用了一个DOM(文档对象模型)的内置方法 {{domxref("document.querySelector()")}} 来选择{{htmlelement("html")}} 元素并且把它存放在一个叫 <code>html</code>的常量中, 这样方便我们接下来使用这个元素:</p> + +<pre class="brush: js notranslate">const html = document.querySelector('html');</pre> + +<p>下段代码使用了另一个名字叫做 {{domxref("Document.createElement()")}} 的DOM方法,用来创建 {{htmlelement("div")}} 元素并且把该新建元素的引用(实际上是新建对象的地址)放在一个叫做 <code>panel</code>的常量中。 这个元素将成为我们的消息框的外部容器。</p> + +<p>然后我们又使用了一个叫做 {{domxref("Element.setAttribute()")}} 的DOM方法给panel元素添加了一个值为<code>msgBox</code> 的<code>class</code> 类属性。 这样做方便我们来给这个元素添加样式 — 查看CSS代码你就知道我们使用<code>.msgBox</code> 类选择器来给消息框和消息内容设置样式。</p> + +<p>最后,我们还使用了一个叫做 {{domxref("Node.appendChild()")}} 的DOM方法,给 <code>html</code> 常量(我们之前定义好的)追加了我们设置好样式的panel元素 。该方法追加了元素的同时也把panel<code><div></code>元素指定为<code><html></code>的子元素 。这样做是因为我们创建了一个元素之后这个元素并不会莫名其妙的出现在我们的页面上(浏览器只知道我们创建了一个元素,但是不知道把这个元素怎么呈现出来) — 因此,我们给这个元素了一个定位,就是显示在html里面!</p> + +<pre class="brush: js notranslate">const panel = document.createElement('div'); +panel.setAttribute('class', 'msgBox'); +html.appendChild(panel);</pre> + +<p>下面这两段使用了我们之前使用过的方法<code>createElement()</code>和<code>appendChild()</code> — 创建了一个 {{htmlelement("p")}} 元素和一个{{htmlelement("button")}}元素 — 并且把他们追加到了panel<code><div></code>之下。我们使用元素的 {{domxref("Node.textContent")}}(Node泛指一个元素并不是说是某个元素是叫Node) 属性— 表示一个元素的文本属性 — 给一个p元素赋值, 同样按钮也有这个属性,该属性就是按钮显示的‘X’。这个按钮的功能就是关闭消息提示框。</p> + +<pre class="brush: js notranslate">const msg = document.createElement('p'); +msg.textContent = 'This is a message box'; +panel.appendChild(msg); + +const closeBtn = document.createElement('button'); +closeBtn.textContent = 'x'; +panel.appendChild(closeBtn);</pre> + +<p>最后我们使用一个叫做 {{domxref("GlobalEventHandlers.onclick")}} 的事件句柄给按钮添加了一个点击事件, 点击事件后定义了一个匿名函数,功能是将消息提示框从父容器中删除 — 达到了关闭的效果。</p> + +<p>简单来说,这个 <code>onclick</code> 句柄是一个按钮的属性 (事实上,页面上的任何元素) 当按钮被点击的时候能够执行一些代码。 你可以在之后的介绍事件的章节了解详情。我们给 <code>onclick</code> 句柄绑定了一个匿名函数, 函数中代码在元素被点击的时候运行。函数里面的这行代码使用了 {{domxref("Node.removeChild()")}} DOM 方法指定了我们想要移除的HTML的子元素 — 在这里指panel<code><div></code>.</p> + +<p>PS:我来解释下是什么意思,panel是消息框,panel.parentNode就是指panel的上一级,就是整个DOM,然后再来用这个父亲来干掉这个儿子,儿子不能自己干掉自己,所以要这么做。</p> + +<pre class="brush: js notranslate">closeBtn.onclick = function() { + panel.parentNode.removeChild(panel); +}</pre> + +<p>大体上, 这一整块的代码我就不解释了就是一个div,一个段落,一个按钮, 把这个加在页面上:</p> + +<pre class="brush: html notranslate"><div class="msgBox"> + <p>This is a message box</p> + <button>x</button> +</div></pre> + +<p>啊,看完了这么多代码,是不是很累? — 不用担心,你现在没有必要完全知道这些代码的细节! 这里我们只关心函数的结构和使用方式, 下面的例子将展示一些有意思的东西。</p> + +<h2 id="调用函数">调用函数</h2> + +<p>相信你已经迫不及待的在你的<code><script></code> 标签中写好了一个函数, 但仅仅是定义而已,这玩意不会做任何事情。</p> + +<ol> + <li>把下面这行代码加在写好的函数下面来调用函数(当然,不一定要放在函数下面来调用,在C语言中确实是还要先定义后使用,但是我们现在用的是JavaScript,这玩意很强大,不管你是先定义后调用还是先调用后定义都行,但是别忘了定义): + <pre class="brush: js notranslate">displayMessage();</pre> + 这行代码调用了你写的函数, 当浏览器解析到这行代码时会立即执行函数内的代码。当你保存好你的代码以后在浏览器中刷新, 你会马上看到一个小小的提示框弹出来, 但是只弹出了一次。毕竟我们只调用了一次函数是不?</li> + <li> + <p>现在打开浏览器开发工具, 找到JavaScript控制台把上面这一句再输入一遍然后回车, 你会看到又弹出了一次!有点意思... — 现在我们有了一个能够重复调用的函数,只要你高兴可以随时调用它。</p> + + <p>但是,这玩意有什么用呢?在真实的应用当中这样的消息提示框一般用来提示一些什么新的东西, 或者是出现了一个什么错误, 或者当用户删除配置文件的时候("你确定要这样做?"), 或者用户添加一个新的联系人之后提示操作成功..等等。 在这个例子里面, 当用户点击这个按钮的时候这个提示框会出现。</p> + </li> + <li>删掉你之前加的那一行代码。</li> + <li>下一步我们用选择器找到这个按钮并赋值给一个常量。 在你的函数定义之前把这行代码加上去: + <pre class="brush: js notranslate">const btn = document.querySelector('button');</pre> + </li> + <li>最后,把这行代码加在上面这行的下面: + <pre class="brush: js notranslate">btn.onclick = displayMessage;</pre> + <code><font face="Open Sans, arial, x-locale-body, sans-serif"><span style="background-color: #ffffff;">跟关闭按钮类似</span></font>closeBtn.onclick...</code> , 当按钮被点击的时候我们运行了点代码。 但不同的是, 之前等号的右边是一个匿名函数,看起来是这样的:<code>btn.onclick = function(){...}</code>, 我们现在是直接使用函数名称来调用。</li> + <li>保存好以后刷新页面 — 现在你应该能看到当你点击按钮的时候提示框弹出来。</li> +</ol> + +<p>你会想“怎么函数名后面没有括号呢?”. 这是因为我们不想直接调用这个函数 — 而是只有当按钮被点击的时候才调用这个函数。 试试把代码改成这样:</p> + +<pre class="brush: js notranslate">btn.onclick = displayMessage();</pre> + +<p>保存刷新, 你会发现按钮都还没点击提示框就出来了! 在函数名后面的这个括号叫做“函数调用运算符”(function invocation operator)。你只有在想直接调用函数的地方才这么写。 同样要重视的是, 匿名函数里面的代码也不是直接运行的, 只要代码在函数作用域内。</p> + +<p>如果你做了这个函数括号的实验, 在继续之前把代码恢复到之前的状态。</p> + +<h2 id="使用参数列表改进函数">使用参数列表改进函数</h2> + +<p>就现在看来,我们的函数还不是特别有用 — 我们想要的不仅仅是每点击一次展示一个默认的消息。我们来改造下我们的函数,给它添加几个参数, 允许我们以不同的方式调用这个函数。</p> + +<ol> + <li>第一步,修改函数的第一行代码: + <pre class="brush: js notranslate">function displayMessage() {</pre> + + <p>改成这样的:</p> + + <pre class="brush: js notranslate">function displayMessage(msgText, msgType) {</pre> + 当我们调用函数的时候,我们可以在括号里添加两个变量,来指定显示在消息框里面的消息,和消息的类型。</li> + <li>为了使用第一个参数, 把接下来的一行: + <pre class="brush: js notranslate">msg.textContent = 'This is a message box';</pre> + + <p>改成这样:</p> + + <pre class="brush: js notranslate">msg.textContent = msgText;</pre> + </li> + <li>最后但同样重要的一点, 我们来调用这个函数,并且使用了带参数的形式,修改下面这行: + <pre class="brush: js notranslate">btn.onclick = displayMessage;</pre> + + <p>改成这样:</p> + + <pre class="brush: js notranslate">btn.onclick = function() { + displayMessage('Woo, this is a different message!'); +};</pre> + 如果我们要在点击事件里面绑定这个新函数,我们不能直接使用(<code>btn.onclick = displayMessage('Woo, this is a different message!');</code>)前面已经讲过— 我们要把它放在一个匿名函数里面,不然函数会直接调用,而不是按钮点击之后才会调用,这不是我们想要的结果。</li> + <li>保存刷新, 就像你所期待的那样现在你可以随意的指定消息框里面显示的消息!</li> +</ol> + +<h3 id="一个更加复杂的参数">一个更加复杂的参数</h3> + +<p>刚才我们只使用了我们定义的第一个参数<code>msgText</code>,对于第二个参数<code>msgType</code>,这个就涉及了稍微多一点的东西— 我们要设置一些依赖于这个 <code>msgType</code> 参数的东西, 我们的函数将会显示不同的图标和不同的背景颜色。</p> + +<ol> + <li>第一步, 从Github上下载我们需要的图标 (<a href="https://raw.githubusercontent.com/mdn/learning-area/master/javascript/building-blocks/functions/icons/warning.png">警告图标</a> 和 <a href="https://raw.githubusercontent.com/mdn/learning-area/master/javascript/building-blocks/functions/icons/chat.png">聊天图标</a>) 。 把图标保存在一个叫做<code>icons</code> 的文件夹下,和你的HTML文件在同一个目录下。 + + <div class="note"><strong>笔记</strong>: 警告和聊天图标是在这个网站iconfinder.com上找到的, 设计者是 <a href="https://www.iconfinder.com/nazarr">Nazarrudin Ansyari</a>. 感谢他!</div> + </li> + <li>下一步, 找到页面的CSS文件. 我们要修改下以便我们使用图标. 首先, 修改 <code>.msgBox</code> 的宽度: + <pre class="brush: css notranslate">width: 200px;</pre> + 改成: + + <pre class="brush: css notranslate">width: 242px;</pre> + </li> + <li>下一步, 在 <code>.msgBox p { ... }</code> 里面添加几条新规则: + <pre class="brush: css notranslate">padding-left: 82px; +background-position: 25px center; +background-repeat: no-repeat;</pre> + </li> + <li>CSS改完了以后我们就要来修改函数 <code>displayMessage()</code> 让它能够显示图标. 在你的函数结束符之前<code>}</code>添加下面这几行代码: + <pre class="brush: js notranslate">if (msgType === 'warning') { + msg.style.backgroundImage = 'url(icons/warning.png)'; + panel.style.backgroundColor = 'red'; +} else if (msgType === 'chat') { + msg.style.backgroundImage = 'url(icons/chat.png)'; + panel.style.backgroundColor = 'aqua'; +} else { + msg.style.paddingLeft = '20px'; +}</pre> + 来解释下, 如果第二个参数 <code>msgType</code> 的值为 <code>'warning'</code>, 我们的消息框将显示一个警告图标和一个红色的背景. 如果这个参数的值是 <code>'chat'</code>, 将显示聊天图标和水蓝色的背景. 如果 <code>msgType</code> 没有指定任何值 (或者不是<code>'warning'</code>和<code>'chat'</code>), 然后这个 <code>else { ... }</code> 代码块将会被执行, 代码的意思是给消息段落设置了一个简单的左内边距并且没有图标, 也没有背景颜色。这么做是为了当没有提供 <code>msgType</code> 参数的时候给函数一个默认行为, 意思是这是一个可选参数(你没发现?其实我们已经用过了!就在这里<code>btn.onclick = function() { displayMessage('Woo, this is a different message!'); };</code>只是当时我们没有写这个<code>else</code>段,也就是啥操作也没做)!</li> + <li>现在来测试下我们的新函数, 可以直接调用 <code>displayMessage()</code> 像这样: + <pre class="brush: js notranslate">displayMessage('Woo, this is a different message!');</pre> + + <p>或者这样:</p> + + <pre class="brush: js notranslate">displayMessage('Your inbox is almost full — delete some mails', 'warning'); +displayMessage('Brian: Hi there, how are you today?','chat');</pre> + 你能看到我们现在的函数稍微有了点用 (不是非常有用) ,一个小的新功能被我们写出来了(当然,函数可以做很多你想的到的和想不到的事)!</li> +</ol> + +<div class="note"> +<p><strong>注意</strong>: 如果你写这个例子遇到了困难, 在这里查看免费的代码 <a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/functions/function-stage-4.html">完整版本的代码</a> (或者<a href="http://mdn.github.io/learning-area/javascript/building-blocks/functions/function-stage-4.html">在线运行的完整代码</a>), 也可以向我们寻求帮助。</p> +</div> + +<h2 id="测试你的技能!"><font face="x-locale-heading-primary, zillaslab, Palatino, Palatino Linotype, x-locale-heading-secondary, serif"><strong>测试你的技能!</strong></font></h2> + +<p>你已经来到了本文章的结尾,但是你还能记得最重要的知识吗?你可以在离开这里找到一些更深度的测试来证实你已经记住了这些知识——查看<a href="https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Building_blocks/Test_your_skills:_Functions">测试你的技能:函数</a>(英文)。后两章文本包含了这个测试需要的技能,所以你可能先需要阅读再尝试该测试。</p> + +<h2 id="结论">结论</h2> + +<p>恭喜你,终于到了这里(等你好久了)! 这篇文章介绍了如何写一个自定义函数, 要把这个新技能在真实项目中使用上你可能还要花点功夫。 下一篇文章中我们将会介绍函数的另一个相关概念 — 返回值。</p> + +<ul> +</ul> + +<p>{{PreviousMenuNext("Learn/JavaScript/Building_blocks/Functions","Learn/JavaScript/Building_blocks/Return_values", "Learn/JavaScript/Building_blocks")}}</p> + +<h2 id="在这个模块中"><font face="x-locale-heading-primary, zillaslab, Palatino, Palatino Linotype, x-locale-heading-secondary, serif"><span style="font-size: 37.33327865600586px;"><strong>在这个模块中</strong></span></font></h2> + +<ul> + <li><a href="/zh-CN/docs/learn/JavaScript/Building_blocks/conditionals">在代码中做决定 - 条件语句 在 Wiki 中编辑</a></li> + <li><a href="/zh-CN/docs/learn/JavaScript/Building_blocks/Looping_code">循环吧代码</a></li> + <li><a href="/zh-CN/docs/learn/JavaScript/Building_blocks/Functions">函数-可复用代码块</a></li> + <li><a href="/zh-CN/docs/learn/JavaScript/Building_blocks/Build_your_own_function">创建您自己的函数</a></li> + <li><a href="/zh-CN/docs/learn/JavaScript/Building_blocks/Return_values">函数返回值</a></li> + <li><a href="/zh-CN/docs/Learn/JavaScript/Building_blocks/Events">事件介绍</a></li> + <li><a href="/zh-CN/docs/learn/JavaScript/Building_blocks/%E7%9B%B8%E7%89%87%E8%B5%B0%E5%BB%8A">照片库</a></li> +</ul> diff --git a/files/zh-cn/learn/javascript/building_blocks/conditionals/index.html b/files/zh-cn/learn/javascript/building_blocks/conditionals/index.html new file mode 100644 index 0000000000..c4135c9e29 --- /dev/null +++ b/files/zh-cn/learn/javascript/building_blocks/conditionals/index.html @@ -0,0 +1,609 @@ +--- +title: 在代码中做决定 - 条件语句 +slug: learn/JavaScript/Building_blocks/conditionals +translation_of: Learn/JavaScript/Building_blocks/conditionals +--- +<div>{{LearnSidebar}}</div> + +<div>{{NextMenu("Learn/JavaScript/Building_blocks/Looping_code", "Learn/JavaScript/Building_blocks")}}</div> + +<p class="summary">在任何的编程语言中,代码需要依靠不同的输入作出决定并且采取行动。例如,在游戏中,如果玩家的生命值变成了0,那么游戏就结束了。在天气应用中,如果在早晨运行,就显示一张日出的图片;如果在晚上,就显示星星和月亮的图片。在这篇文章中,我们将探索在JavaScript中所谓的条件语句是怎样工作的。</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">预备知识:</th> + <td>基本的计算机知识,对HTML和CSS有基本的了解,<a href="https://developer.mozilla.org/en-US/docs/Learn/JavaScript/First_steps">JavaScript的第一步</a>。</td> + </tr> + <tr> + <th scope="row">目标:</th> + <td>了解怎样在JavaScript中使用条件语句的结构。</td> + </tr> + </tbody> +</table> + +<h2 id="只需一个条件你就可以拥有……!">只需一个条件你就可以拥有……!</h2> + +<p>人类(以及其他的动物)无时无刻不在做决定,这些决定都影响着他们的生活,从小事(“我应该吃一片还是两片饼干”)到重要的大事(“我应该留在我的祖国,在我父亲的农场工作;还是应该去美国学习天体物理学”)。</p> + +<p>条件语句结构允许我们来描述在JavaScript中这样的选择,从不得不作出的选择(例如:“一片还是两片”)到产生的结果或这些选择(也许是“吃一片饼干”可能会“仍然感觉饿”,或者是“吃两片饼干”可能会“感觉饱了,但妈妈会因为我吃掉了所有的饼干而骂我”。)</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/13703/cookie-choice-small.png" style="display: block; margin: 0 auto;"></p> + +<h2 id="if_..._else_语句">if ... else 语句</h2> + +<p><code><font face="Open Sans, arial, sans-serif">让我们看看到目前为止你将会在JavaScript中用到的最常见的条件语句类型 — </font><a href="/en-US/docs/Web/JavaScript/Reference/Statements/if...else">if ... else语句</a>。</code></p> + +<h3 id="基本的的_if…else_语法">基本的的 if…else 语法</h3> + +<p>基本的if…else语法看起来像下面的 {{glossary("伪代码")}}:</p> + +<pre class="notranslate">if (condition) { + code to run if condition is true +} else { + run some other code instead +}</pre> + +<p>在这里我们有:</p> + +<ol> + <li>关键字 if,并且后面跟随括号。</li> + <li>要测试的条件,放到括号里(通常是“这个值大于另一个值吗”或者“这个值存在吗”)。这个条件会利用<a href="https://developer.mozilla.org/en-US/Learn/JavaScript/First_steps/Math#Comparison_operators">比较运算符</a>(我们会在最后的模块中讨论)进行比较,并且返回true或者false。</li> + <li>一组花括号,在里面我们有一些代码——可以是任何我们喜欢的代码,并且只会在条件语句返回true的时候运行。</li> + <li>关键字else。</li> + <li>另一组花括号,在里面我们有一些代码——可以是任何我们喜欢的代码,并且当条件语句返回值不是true的话,它才会运行。</li> +</ol> + +<p>这段代码真的非常易懂——它说“<strong>如果(if)条件(condition)</strong>返回true,运行代码A,<strong>否则(else)</strong>运行代码B”</p> + +<p>注意:你不一定需要else和第二个花括号——下面的代码也是符合语法规则的:</p> + +<pre class="notranslate">if (condition) { + code to run if condition is true +} + +run some other code</pre> + +<p>不过,这里你需要注意——在这种情况下,第二段代码不被条件语句控制,所以它总会运行,不管条件返回的是true还是false。这不一定是一件坏事,但这可能不是你想要的——你经常只想要运行一段代码或者另一段,而不是两个都运行。</p> + +<p>最后,有时候你可能会看到 if…else 语句没有写花括号,像下面的速记风格:</p> + +<pre class="notranslate">if (condition) code to run if condition is true +else run some other code instead</pre> + +<p>这是完全有效的代码,但不建议这样使用——因为如果有花括号进行代码切割的话,整体代码被切割为多行代码,更易读和易用。</p> + +<h3 id="一个真实的例子">一个真实的例子</h3> + +<p>为了更好的理解这种语法,让我们考虑一个真实的例子。想像一个孩子被他的父母要求帮助他们做家务。父母可能会说“嗨,宝贝儿,如果你帮我去购物,我会给你额外的零花钱,这样你就能买得起你想要的玩具了。”在JavaScript中,我们可以这样表示:</p> + +<pre class="brush: js notranslate">var shoppingDone = false; + +if (shoppingDone === true) { + var childsAllowance = 10; +} else { + var childsAllowance = 5; +}</pre> + +<p>这段代码显示的结果是变量 <code>shoppingDone </code>总是返回 <code>false</code>, 意味着对我们的穷孩子来说很失望。如果孩子去购物的话,就需要依靠我们提供机制来使父母把变量 <code>shoppingDone</code> 变成 <code>true</code>。</p> + +<div class="note"> +<p><strong>Note</strong>: 你可以看到在<a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/allowance-updater.html">Github上这个例子的完整版本</a>(也可以<a href="http://mdn.github.io/learning-area/javascript/building-blocks/allowance-updater.html">在线运行</a>)</p> +</div> + +<h3 id="else_if">else if</h3> + +<p>最后一个例子提供给我们两个选择或结果,但是如果我们想要两个以上呢?</p> + +<p>有一种方法来让你的 <code>if…else </code>连接你的额外的选择和结果——使用<code>else if </code>。每一个额外的选择要求放到 <code>if() { ... }</code> 和 <code>else { ... }</code> 里——看看下面更多涉及到的例子,它们属于一个普通的天气预报的应用的一部分。</p> + +<pre class="brush: html notranslate"><label for="weather">Select the weather type today: </label> +<select id="weather"> + <option value="">--Make a choice--</option> + <option value="sunny">Sunny</option> + <option value="rainy">Rainy</option> + <option value="snowing">Snowing</option> + <option value="overcast">Overcast</option> +</select> + +<p></p></pre> + +<pre class="brush: js notranslate">var select = document.querySelector('select'); +var para = document.querySelector('p'); + +select.addEventListener('change', setWeather); + +function setWeather() { + var choice = select.value; + + if (choice === 'sunny') { + para.textContent = 'It is nice and sunny outside today. Wear shorts! Go to the beach, or the park, and get an ice cream.'; + } else if (choice === 'rainy') { + para.textContent = 'Rain is falling outside; take a rain coat and a brolly, and don\'t stay out for too long.'; + } else if (choice === 'snowing') { + para.textContent = 'The snow is coming down — it is freezing! Best to stay in with a cup of hot chocolate, or go build a snowman.'; + } else if (choice === 'overcast') { + para.textContent = 'It isn\'t raining, but the sky is grey and gloomy; it could turn any minute, so take a rain coat just in case.'; + } else { + para.textContent = ''; + } +} + +</pre> + +<p>{{ EmbedLiveSample('else_if', '100%', 100) }}</p> + +<ol> + <li>这里我们有 HTML {{htmlelement("select")}} 元素让我们选择不同的天气,以及一个简单的段落。</li> + <li>在 JavaScript 中, 我们同时存储了对 {{htmlelement("select")}} 和 {{htmlelement("p")}} 的引用, 并对 <code><select></code> 添加了一个事件监听器,因此,当它的值改变时,<code>setWeather()</code>函数被执行。</li> + <li>当函数运行时,我们首先新建了一个 <code>choice</code> 变量去存储当前被选的 <code><select></code> 中的值。接着我们用条件判断语句根据 <code>choice</code> 的值选择性的展示段落中的文本。注意 <code>else if() {...}</code>段中的条件是怎么被判断的,除了第一个,它是在 <code>if() {...}中被判断的。</code></li> + <li>最后一个 <code>else {...}</code> 中的选择通常被叫做 “最后招数” — 在所有的条件都不为 true 时其中的代码会被执行。在这个例子中,如果用户没有选择任何一个选项,它会将段落中的文本清空,例如当用户决定重新选择最开始出现的"--Make a choice--"选项时,就会有这样的效果。</li> +</ol> + +<div class="note"> +<p><strong>Note</strong>: 你可以 <a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/simple-else-if.html">在 GitHub 上找到这个例子</a> (也可以<a href="http://mdn.github.io/learning-area/javascript/building-blocks/simple-else-if.html">在线运行</a>。)</p> +</div> + +<h3 id="关于比较运算符">关于比较运算符</h3> + +<p>比较运算符是用来判断条件语句中的条件的。我们先回过头来看看<a href="/en-US/Learn/JavaScript/First_steps/Math#Comparison_operators">Basic math in JavaScript — numbers and operators</a> 文章中的比较运算符。我们有如下选择:</p> + +<ul> + <li><code>===</code> 和 <code>!==</code> — 判断一个值是否严格等于,或不等于另一个。</li> + <li><code><</code> 和 <code>></code> — 判断一个值是否小于,或大于另一个。</li> + <li><code><=</code> 和 <code>>=</code> — 判断一个值是否小于或等于,或者大于或等于另一个。</li> +</ul> + +<div class="note"> +<p><strong>Note</strong>: 如果你想复习这些内容,可以回顾之前链接上的材料。</p> +</div> + +<p>我们想特别提到测试布尔值(true / false),和一个通用模式,你会频繁遇到它,任何不是 <code>false</code>, <code>undefined</code>, <code>null</code>, <code>0</code>, <code>NaN</code> 的值,或一个空字符串('')在作为条件语句进行测试时实际返回true,因此您可以简单地使用变量名称来测试它是否为真,甚至是否存在(即它不是未定义的)。例如: </p> + +<pre class="brush: js notranslate">var cheese = 'Cheddar'; + +if (cheese) { + console.log('Yay! Cheese available for making cheese on toast.'); +} else { + console.log('No cheese on toast for you today.'); +}</pre> + +<p>而且,回到我们以前关于孩子为自己的父母做家务的例子,你可以这样写:</p> + +<pre class="brush: js notranslate">var shoppingDone = false; + +if (shoppingDone) { // don't need to explicitly specify '=== true' + var childsAllowance = 10; +} else { + var childsAllowance = 5; +}</pre> + +<h3 id="嵌套if_..._else">嵌套if ... else</h3> + +<p>将另一个if ... else 语句放在另一个中 - 嵌套它是完全可行的。例如,我们可以更新我们的天气预报应用程序,以显示更多的选择,具体取决于温度:</p> + +<pre class="brush: js notranslate">if (choice === 'sunny') { + if (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.'; + } else if (temperature >= 86) { + para.textContent = 'It is ' + temperature + ' degrees outside — REALLY HOT! If you want to go outside, make sure to put some suncream on.'; + } +}</pre> + +<p>即使代码全部一起工作,每个if ... else语句完全独立于另一个。</p> + +<h3 id="逻辑运算符:_和_!">逻辑运算符:&& , || 和 !</h3> + +<p>如果要测试多个条件,而不需要编写嵌套if ... else语句,逻辑运算符可以帮助您。当在条件下使用时,前两个执行以下操作:</p> + +<ul> + <li><code>&&</code> — 逻辑与; 使得并列两个或者更多的表达式成为可能,只有当这些表达式每一个都返回<code>true</code>时,整个表达式才会返回<code>true.</code></li> + <li><code>||</code> — 逻辑或; 当两个或者更多表达式当中的任何一个返回 <code>true</code> 则整个表达式将会返回 <code>true</code>.</li> + <li>! — 逻辑非; 对一个布尔值取反, 非true返回false,非false返回true.</li> +</ul> + +<p>举一个逻辑 && 的例子, 刚才的那段代码片段可以写成下面这样:</p> + +<pre class="brush: js notranslate">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.'; +} else if (choice === 'sunny' && temperature >= 86) { + para.textContent = 'It is ' + temperature + ' degrees outside — REALLY HOT! If you want to go outside, make sure to put some suncream on.'; +}</pre> + +<p>所以,只有当<code>choice === 'sunny'</code>并且<code>temperature < 86</code>都返回<code>true</code>时,第一个代码块才能运行。</p> + +<p>让我们快速看一个 <strong>|| </strong>的例子:</p> + +<pre class="brush: js notranslate">if (iceCreamVanOutside || houseStatus === 'on fire') { + console.log('You should leave the house quickly.'); +} else { + console.log('Probably should just stay in then.'); +}</pre> + +<p>最后一种类型的逻辑运算符, <strong>逻辑非<strong><code>!</code></strong> </strong>运算符表示, 可以用于对一个表达式取否. 让我们把 <strong> 非运算符 </strong>结合上一个例子里的<strong> 或表达式 </strong>看看:</p> + +<pre class="brush: js notranslate">if (!(iceCreamVanOutside || houseStatus === 'on fire')) { + console.log('Probably should just stay in then.'); +} else { + console.log('You should leave the house quickly.'); +}</pre> + +<p>在这一段代码中,如果<strong>逻辑或</strong>所在的语句返回 <code>true</code>,则<strong>非运算符</strong>会将其取否,于是整个表达式的返回值将会是<code>false</code>。</p> + +<p>您可以在任何结构中随意合并很多个逻辑表达式。接下来的例子将会只在<strong>或运算符</strong>两边的语句同时返回true时才会执行代码,这也就意味着整个<strong>与运算符</strong>语句将会返回true:</p> + +<pre class="brush: js notranslate">if ((x === 5 || y > 3 || z <= 10) && (loggedIn || userName === 'Steve')) { + // run the code +}</pre> + +<p>在条件语句中运用<strong>或逻辑运算符</strong>最常见的错误是尝试声明变量后,仅检查该变量一次的情况下赋予很多个都会返回true的值,不同的值之间用 <code>||</code> (或)运算符分隔。比如:</p> + +<pre class="example-bad brush: js notranslate">if (x === 5 || 7 || 10 || 20) { + // run my code +}</pre> + +<p>在这个例子里 <code>if(...)</code> 里的条件总为真,因为 7 (或者其它非零的数) 的值总是为真. 这个条件实际意思是 "如果x等于5, 或者7为真 — 它总是成立的". 这不是我们想要的逻辑,为了 让它正常工作你必须指定每个或<strong>表达式</strong>两边都是完整的检查:</p> + +<pre class="brush: js notranslate">if (x === 5 || x === 7 || x === 10 ||x === 20) { + // run my code +}</pre> + +<h2 id="switch语句">switch语句</h2> + +<p><code>if...else</code> 语句能够很好地实现条件代码,但是它们不是没有缺点。 它们主要适用于您只有几个选择的情况,每个都需要相当数量的代码来运行,和/或 的条件很复杂的情况(例如多个逻辑运算符)。 对于只想将变量设置一系列为特定值的选项或根据条件打印特定语句的情况,语法可能会很麻烦,特别是如果您有大量选择。</p> + +<p><a href="/en-US/docs/Web/JavaScript/Reference/Statements/switch"><code>switch</code> </a>语句在这里是您的朋友 - 他们以单个表达式/值作为输入,然后查看多个选项,直到找到与该值相匹配的选项,执行与之相关的代码。 这里有一些伪代码,可以给你一点灵感:</p> + +<pre class="notranslate">switch (expression) { + case choice1: + run this code + break; + + case choice2: + run this code instead + break; + + // include as many cases as you like + + default: + actually, just run this code +}</pre> + +<p>这里我们得到:</p> + +<ol> + <li>关键字 <code>switch</code>, 后跟一组括号.</li> + <li>括号内的表达式或值.</li> + <li>关键字 <code>case</code>, 后跟一个选项的表达式/值,后面跟一个冒号.</li> + <li>如果选择与表达式匹配,则运行一些代码.</li> + <li>一个 <code>break</code> 语句, 分号结尾. 如果先前的选择与表达式/值匹配,则浏览器在此停止执行代码块,并执行switch语句之后的代码.</li> + <li>你可以添加任意的 case 选项(选项3-5).</li> + <li>关键字 <code>default</code>, 后面跟随和 <code>case</code> 完全相同的代码模式 (选项 3–5), except that <code>default</code> 之后不需要再有选项, 并且您不需要 <code>break</code> 语句, 因为之后没有任何运行代码. 如果之前没有选项匹配,则运行<code>default</code>选项.</li> +</ol> + +<div class="note"> +<p><strong>Note</strong>: <code>default</code> 部分不是必须的 - 如果表达式不可能存在未知值,则可以安全地省略它。 如果有机会,您需要包括它来处理未知的情况。</p> +</div> + +<h3 id="switch语句示例">switch语句示例</h3> + +<p>我们来看一个真实的例子 - 我们将重写天气预报应用程序,以改用switch语句:</p> + +<pre class="brush: html notranslate"><label for="weather">Select the weather type today: </label> +<select id="weather"> + <option value="">--Make a choice--</option> + <option value="sunny">Sunny</option> + <option value="rainy">Rainy</option> + <option value="snowing">Snowing</option> + <option value="overcast">Overcast</option> +</select> + +<p></p></pre> + +<pre class="brush: js notranslate">var select = document.querySelector('select'); +var para = document.querySelector('p'); + +select.addEventListener('change', setWeather); + + +function setWeather() { + var choice = select.value; + + switch (choice) { + case 'sunny': + para.textContent = 'It is nice and sunny outside today. Wear shorts! Go to the beach, or the park, and get an ice cream.'; + break; + case 'rainy': + para.textContent = 'Rain is falling outside; take a rain coat and a brolly, and don\'t stay out for too long.'; + break; + case 'snowing': + para.textContent = 'The snow is coming down — it is freezing! Best to stay in with a cup of hot chocolate, or go build a snowman.'; + break; + case 'overcast': + para.textContent = 'It isn\'t raining, but the sky is grey and gloomy; it could turn any minute, so take a rain coat just in case.'; + break; + default: + para.textContent = ''; + } +}</pre> + +<p>{{ EmbedLiveSample('A_switch_example', '100%', 100) }}</p> + +<div class="note"> +<p><strong>Note</strong>: 你可以 <a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/simple-switch.html">在 GitHub 上找到这个例子</a> (也可以<a href="http://mdn.github.io/learning-area/javascript/building-blocks/simple-switch.html">在线运行</a>。)</p> +</div> + +<h2 id="三元运算符">三元运算符</h2> + +<p><font><font>在我们举一些例子之前,我们要介绍一下最后一句语法。</font></font><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Conditional_Operator"><font><font>三元或条件运算符</font></font></a><font><font>是一个语法的小点,用于测试一个条件,并返回一个值/表达,如果它是</font></font><code>true</code><font><font>,另一个是</font></font><code>false</code><font><font>-这种情况下是有用的,并且可以占用比</font></font><code>if...else</code><font><font>块较少的代码块。如果你只有两个通过</font></font><code>true</code><font><font>/ </font></font><code>false</code><font><font>条件</font><font>选择</font><font>。</font><font>伪代码看起来像这样:</font></font></p> + +<pre class="notranslate">( condition ) ? run this code : run this code instead</pre> + +<p>所以我们来看一个简单的例子:</p> + +<pre class="brush: js notranslate">var greeting = ( isBirthday ) ? 'Happy birthday Mrs. Smith — we hope you have a great day!' : 'Good morning Mrs. Smith.';</pre> + +<p><font><font>在这里我们有一个变量叫做</font></font><code>isBirthday</code><font><font>- 如果它是</font></font><code>true</code><font><font>,我们给客人一个生日快乐的消息; </font><font>如果不是,我们给她标准的每日问候。</font></font></p> + +<h3 id="三元运算符示例">三元运算符示例</h3> + +<p>你不需要用三元运算符设置变量值; 你也可以运行任何你喜欢的函数或代码行。以下实例显示了一个简单的主题选择器,其中该站点的样式应用了三元运算符。</p> + +<pre class="brush: html notranslate"><label for="theme">Select theme: </label> +<select id="theme"> + <option value="white">White</option> + <option value="black">Black</option> +</select> + +<h1>This is my website</h1></pre> + +<pre class="brush: js notranslate">var select = document.querySelector('select'); +var html = document.querySelector('html'); +document.body.style.padding = '10px'; + +function update(bgColor, textColor) { + html.style.backgroundColor = bgColor; + html.style.color = textColor; +} + +select.onchange = function() { + ( select.value === 'black' ) ? update('black','white') : update('white','black'); +} +</pre> + +<p>{{ EmbedLiveSample('Ternary_operator_example', '100%', 300) }}</p> + +<p><font><font>在这里,我们有一个</font></font><a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/select" title="HTML <select>元素表示一个控件,提供一个选项菜单:"><code><select></code></a><font><font>选择主题(黑色或白色)</font><font>的</font><font>元素,加上一个简单</font></font><a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/h1" title="标题元素实现六个级别的文档标题,<h1>是最重要的,<h6>是最少的。 标题元素简要介绍了它介绍的部分的主题。 标题信息可以由用户代理使用,例如,自动构建文档的目录。"><code><h1></code></a><font><font>的显示网站标题。</font><font>我们也有一个函数叫做</font></font><code>update()</code><font><font>,它将两种颜色作为参数(输入)。</font><font>网站的背景颜色设置为第一个提供的颜色,其文本颜色设置为第二个提供的颜色。</font></font></p> + +<p><font><font>最后,我们还有一个</font></font><a href="https://developer.mozilla.org/en-US/docs/Web/API/GlobalEventHandlers/onchange"><font><font>onchange</font></font></a><font><font>事件监听器,用于运行一个包含三元运算符的函数。</font><font>它以测试条件开始</font></font><code>select.value === 'black'</code><font><font>。</font><font>如果这返回</font></font><code>true</code><font><font>,我们运行</font></font><code>update()</code><font><font>带有黑色和白色参数</font><font>的</font><font>函数,这意味着我们最终得到黑色的背景颜色和白色的文字颜色。</font><font>如果返回</font></font><code>false</code><font><font>,我们运行</font></font><code>update()</code><font><font>带有白色和黑色参数</font><font>的</font><font>函数,这意味着站点颜色被反转。</font></font></p> + +<div class="note"> +<p><strong>Note</strong>: 你可以 <a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/simple-ternary.html">在 GitHub 上找到这个例子</a> (也可以<a href="http://mdn.github.io/learning-area/javascript/building-blocks/simple-ternary.html">在线运行</a>。)</p> +</div> + +<h2 id="主动学习:一个简单的日历">主动学习:一个简单的日历</h2> + +<p><font><font>在这个例子中,您将帮助我们完成一个简单的日历应用程序。</font><font>在你的代码中:</font></font></p> + +<ul> + <li><font><font>一个</font></font><a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/select" title="HTML <select>元素表示一个控件,提供一个选项菜单:"><code><select></code></a><font><font>元素,允许用户在不同月份之间进行选择。</font></font></li> + <li><code>onchange</code><font><font>检测</font></font><code><select></code><font><font>菜单中</font><font>选择的值何时</font><font>更改</font><font>的</font><font>事件处理程序</font><font>。</font></font></li> + <li><font><font>一个函数叫做</font></font><code>createCalendar()</code><font><font>绘制日历并在</font></font><a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/h1" title="标题元素实现六个级别的文档标题,<h1>是最重要的,<h6>是最少的。 标题元素简要介绍了它介绍的部分的主题。 标题信息可以由用户代理使用,例如,自动构建文档的目录。"><code><h1></code></a><font><font>元素中</font><font>显示正确的月份</font><font>。</font></font></li> +</ul> + +<p><font><font>我们需要你在</font></font><code>onchange</code><font><font>处理函数中</font><font>写一个条件语句</font><font>,就在</font></font><code>// ADD CONDITIONAL HERE</code><font><font>任务的</font><font>下面 </font><font>。</font><font>这应该:</font></font></p> + +<ol> + <li><font><font>查看所选月份(存储在</font></font><code>choice</code><font><font>变量中,这将是</font></font><code><select></code><font><font>值更改后的元素值,例如“1月”)。</font></font></li> + <li><font><font>设置一个被调用</font></font><code>days</code><font><font>为等于所选月份天数的</font><font>变量</font><font>。</font><font>为此,您必须查看一年中每个月的天数。</font><font>为了这个例子的目的,你可以忽略闰年。</font></font></li> +</ol> + +<p>提示:</p> + +<ul> + <li><font><font>建议您使用逻辑或将多个月组合成一个单一条件; </font><font>他们中的许多人共享相同的天数。</font></font></li> + <li><font><font>考虑最常用的天数,并将其用作默认值。</font></font></li> +</ul> + +<p><font>如果您犯了错误,您可以随时使用“Reset”按钮重置该示例。</font><font>如果真的卡住了,请按“Show solution”查看解决方案。</font></p> + +<div class="hidden"> +<h6 id="Playable_code">Playable code</h6> + +<pre class="brush: html notranslate"><div class="output" style="height: 500px;overflow: auto;"> + <label for="month">Select month: </label> + <select id="month"> + <option value="January">January</option> + <option value="February">February</option> + <option value="March">March</option> + <option value="April">April</option> + <option value="May">May</option> + <option value="June">June</option> + <option value="July">July</option> + <option value="August">August</option> + <option value="September">September</option> + <option value="October">October</option> + <option value="November">November</option> + <option value="December">December</option> + </select> + + <h1></h1> + + <ul></ul> +</div> + +<hr> + +<textarea id="code" class="playable-code" style="height: 500px;"> +var select = document.querySelector('select'); +var list = document.querySelector('ul'); +var h1 = document.querySelector('h1'); + +select.onchange = function() { + var choice = select.value; + + // ADD CONDITIONAL HERE + + createCalendar(days, choice); +} + +function createCalendar(days, choice) { + list.innerHTML = ''; + h1.textContent = choice; + for (var i = 1; i <= days; i++) { + var listItem = document.createElement('li'); + listItem.textContent = i; + list.appendChild(listItem); + } +} + +createCalendar(31,'January'); +</textarea> + +<div class="playable-buttons"> + <input id="reset" type="button" value="Reset"> + <input id="solution" type="button" value="Show solution"> +</div> +</pre> + +<pre class="brush: css notranslate">.output * { + box-sizing: border-box; +} + +.output ul { + padding-left: 0; +} + +.output li { + display: block; + float: left; + width: 25%; + border: 2px solid white; + padding: 5px; + height: 40px; + background-color: #4A2DB6; + color: white; +} +</pre> + +<pre class="brush: js notranslate">var textarea = document.getElementById('code'); +var reset = document.getElementById('reset'); +var solution = document.getElementById('solution'); +var code = textarea.value; + +function updateCode() { + eval(textarea.value); +} + +reset.addEventListener('click', function() { + textarea.value = code; + updateCode(); +}); + +solution.addEventListener('click', function() { + textarea.value = jsSolution; + updateCode(); +}); + +var jsSolution = 'var select = document.querySelector(\'select\');\nvar list = document.querySelector(\'ul\');\nvar h1 = document.querySelector(\'h1\');\n\nselect.onchange = function() {\n var choice = select.value;\n var days = 31;\n if(choice === \'February\') {\n days = 28;\n } else if(choice === \'April\' || choice === \'June\' || choice === \'September\'|| choice === \'November\') {\n days = 30;\n }\n\n createCalendar(days, choice);\n}\n\nfunction createCalendar(days, choice) {\n list.innerHTML = \'\';\n h1.textContent = choice;\n for(var i = 1; i <= days; i++) {\n var listItem = document.createElement(\'li\');\n listItem.textContent = i;\n list.appendChild(listItem);\n }\n }\n\ncreateCalendar(31,\'January\');'; + +textarea.addEventListener('input', updateCode); +window.addEventListener('load', updateCode); +</pre> +</div> + +<p>{{ EmbedLiveSample('Playable_code', '100%', 1110) }}</p> + +<h2 id="主动学习:更多颜色选择!">主动学习:更多颜色选择!</h2> + +<p><font><font>在这个例子中,您将要采取我们前面看到的三元运算符示例,并将三元运算符转换为一个switch语句,这将允许我们对简单的网站应用更多的选择。</font><font>看看</font></font><a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/select" title="HTML <select>元素表示一个控件,提供一个选项菜单:"><code><select></code></a><font><font>- 这次你会看到它不是两个主题选项,而是五个。</font><font>您需要在</font></font><code>// ADD SWITCH STATEMENT</code><font><font>注释</font><font>下面添加一个switch语句</font><font>:</font></font></p> + +<ul> + <li><font><font>它应该接受</font></font><code>choice</code><font><font>变量作为其输入表达式。</font></font></li> + <li><font><font>对于每种情况,选择应该等于可以选择的可能值之一,即白色,黑色,紫色,黄色或迷幻色。</font></font></li> + <li><font><font>对于每种情况,应运行</font></font><code>update()</code><font><font>函数,并传递两个颜色值,第一个颜色值为背景颜色,第二个颜色值为文本颜色。</font><font>请记住,颜色值是字符串,因此需要用引号括起来。</font></font></li> +</ul> + +<p><font>如果您犯了错误,您可以随时使用“Reset”按钮重置该示例。</font><font>如果真的卡住了,请按“Show solution”查看解决方案。</font></p> + +<div class="hidden"> +<h6 id="Playable_code_2">Playable code 2</h6> + +<pre class="brush: html notranslate"><div class="output" style="height: 300px;"> + <label for="theme">Select theme: </label> + <select id="theme"> + <option value="white">White</option> + <option value="black">Black</option> + <option value="purple">Purple</option> + <option value="yellow">Yellow</option> + <option value="psychedelic">Psychedelic</option> + </select> + + <h1>This is my website</h1> +</div> + +<hr> + +<textarea id="code" class="playable-code" style="height: 450px;"> +var select = document.querySelector('select'); +var html = document.querySelector('.output'); + +select.onchange = function() { + var choice = select.value; + + // ADD SWITCH STATEMENT +} + +function update(bgColor, textColor) { + html.style.backgroundColor = bgColor; + html.style.color = textColor; +}</textarea> + +<div class="playable-buttons"> + <input id="reset" type="button" value="Reset"> + <input id="solution" type="button" value="Show solution"> +</div> +</pre> + +<pre class="brush: js notranslate">var textarea = document.getElementById('code'); +var reset = document.getElementById('reset'); +var solution = document.getElementById('solution'); +var code = textarea.value; + +function updateCode() { + eval(textarea.value); +} + +reset.addEventListener('click', function() { + textarea.value = code; + updateCode(); +}); + +solution.addEventListener('click', function() { + textarea.value = jsSolution; + updateCode(); +}); + +var jsSolution = 'var select = document.querySelector(\'select\');\nvar html = document.querySelector(\'.output\');\n\nselect.onchange = function() {\n var choice = select.value;\n\n switch(choice) {\n case \'black\':\n update(\'black\',\'white\');\n break;\n case \'white\':\n update(\'white\',\'black\');\n break;\n case \'purple\':\n update(\'purple\',\'white\');\n break;\n case \'yellow\':\n update(\'yellow\',\'darkgray\');\n break;\n case \'psychedelic\':\n update(\'lime\',\'purple\');\n break;\n }\n}\n\nfunction update(bgColor, textColor) {\n html.style.backgroundColor = bgColor;\n html.style.color = textColor;\n}'; + +textarea.addEventListener('input', updateCode); +window.addEventListener('load', updateCode); +</pre> +</div> + +<p>{{ EmbedLiveSample('Playable_code_2', '100%', 850) }}</p> + +<h2 id="结论">结论</h2> + +<p><font><font>这就是现在您真正需要了解的JavaScript中的条件结构!</font><font>我相信你会理解这些概念,并轻松地通过这些例子; </font><font>如果有什么不明白的,请随时阅读文章,或者</font></font><a href="https://developer.mozilla.org/en-US/Learn#Contact_us"><font><font>联系我们</font></font></a><font><font>寻求帮助。</font></font></p> + +<h2 id="参见">参见</h2> + +<ul> + <li><a href="https://developer.mozilla.org/en-US/Learn/JavaScript/First_steps/Math#Comparison_operators"><font><font>比较运算符</font></font></a></li> + <li><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Control_flow_and_error_handling#Conditional_statements"><font><font>条件声明详细</font></font></a></li> + <li><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/if...else"><font><font>如果...其他参考</font></font></a></li> + <li><font><font><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Conditional_Operator">条件(三元)运算符引用</a></font></font></li> +</ul> + +<p>{{NextMenu("Learn/JavaScript/Building_blocks/Looping_code", "Learn/JavaScript/Building_blocks")}}</p> diff --git a/files/zh-cn/learn/javascript/building_blocks/events/index.html b/files/zh-cn/learn/javascript/building_blocks/events/index.html new file mode 100644 index 0000000000..605a4efae0 --- /dev/null +++ b/files/zh-cn/learn/javascript/building_blocks/events/index.html @@ -0,0 +1,564 @@ +--- +title: 事件介绍 +slug: Learn/JavaScript/Building_blocks/Events +tags: + - Event + - Guide + - JavaScript + - 事件 + - 事件处理 + - 初学者 +translation_of: Learn/JavaScript/Building_blocks/Events +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/JavaScript/Building_blocks/Return_values","Learn/JavaScript/Building_blocks/Image_gallery", "Learn/JavaScript/Building_blocks")}}</div> + +<p class="summary">事件是您在编程时系统内发生的动作或者发生的事情,系统响应事件后,如果需要,您可以某种方式对事件做出回应。例如:如果用户在网页上单击一个按钮,您可能想通过显示一个信息框来响应这个动作。在这篇文章中,我们将讨论一些关于事件的重要概念,并且观察它们在浏览器上如何运行。这篇文章不会面面俱到,仅聚焦于您现阶段需要掌握的知识。</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">前提:</th> + <td>基本电脑知识, 对HTML和CSS的基本了解,及 <a href="/en-US/docs/Learn/JavaScript/First_steps">JavaScript first steps</a>.</td> + </tr> + <tr> + <th scope="row">目标:</th> + <td>了解事件的基本理论,它们怎么在浏览器上运行的,以及在不同的编程环境下事件有何不同。</td> + </tr> + </tbody> +</table> + +<h2 id="一系列事件">一系列事件</h2> + +<p>就像上面提到的, <strong>事件</strong>是您在编程时系统内发生的动作或者发生的事情——系统会在事件出现时产生或触发某种信号,并且会提供一个自动加载某种动作(列如:运行一些代码)的机制,比如在一个机场,当跑道清理完成,飞机可以起飞时,飞行员会收到一个信号,因此他们开始起飞。</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/14077/MDN-mozilla-events-runway.png" style="display: block; margin: 0px auto;"></p> + +<p>在 Web 中, 事件在浏览器窗口中被触发并且通常被绑定到窗口内部的特定部分 — 可能是一个元素、一系列元素、被加载到这个窗口的 HTML 代码或者是整个浏览器窗口。举几个可能发生的不同事件:</p> + +<ul> + <li>用户在某个元素上点击鼠标或悬停光标。</li> + <li>用户在键盘中按下某个按键。</li> + <li>用户调整浏览器的大小或者关闭浏览器窗口。</li> + <li>一个网页停止加载。</li> + <li>提交表单。</li> + <li>播放、暂停、关闭视频。</li> + <li>发生错误。</li> +</ul> + +<p>如果您想看看更多其他的事件 ,请移步至MDN的<a href="/en-US/docs/Web/Events">Event reference</a>。</p> + +<p>每个可用的事件都会有一个<strong>事件处理器</strong>,也就是事件触发时会运行的代码块。当我们定义了一个用来回应事件被激发的代码块的时候,我们说我们<strong>注册了一个事件处理器</strong>。注意事件处理器有时候被叫做<strong>事件监听器</strong>——从我们的用意来看这两个名字是相同的,尽管严格地来说这块代码既监听也处理事件。监听器留意事件是否发生,然后处理器就是对事件发生做出的回应。</p> + +<div class="note"> +<p><strong>注:</strong> 网络事件不是 JavaScript 语言的核心——它们被定义成内置于浏览器的 JavaScript APIs。</p> +</div> + +<h3 id="一个简单的例子">一个简单的例子</h3> + +<p>让我们看一个简单的例子。前面您已经见到过很多事件和事件监听器,现在我们概括一下以巩固我们的知识。在接下来的例子中,我们的页面中只有一个 button,按下时,背景会变成随机的一种颜色。</p> + +<pre class="brush: html notranslate"><button>Change color</button></pre> + +<div class="hidden"> +<pre class="brush: css notranslate">button { margin: 10px };</pre> +</div> + +<p>JavaScript代码如下所示:</p> + +<pre class="brush: js notranslate">const btn = document.querySelector('button'); + +function random(number) { + return Math.floor(Math.random()*(number+1)); +} + +btn.onclick = function() { + const rndCol = 'rgb(' + random(255) + ',' + random(255) + ',' + random(255) + ')'; + document.body.style.backgroundColor = rndCol; +}</pre> + +<p>我们使用 <code>btn</code> 变量存储 button,并使用了<code>Document.querySelector()</code> 函数。我们也定义了一个返回随机数字的函数。代码第三部分就是事件处理器。<code>btn</code>变量指向 button 元素,在 button 这种对象上可触发一系列的事件,因此也就可以使用事件处理器。我们通过将一个匿名函数(这个赋值函数包括生成随机色并赋值给背景色的代码)赋值给“点击”事件处理器参数,监听“点击”这个事件。</p> + +<p>只要点击事件在<code><button></code>元素上触发,该段代码就会被执行。即每当用户点击它时,都会运行此段代码。</p> + +<p>示例输出如下:</p> + +<p>{{ EmbedLiveSample('A_simple_example', '100%', 200, "", "", "hide-codepen-jsfiddle") }}</p> + +<h3 id="这不仅应用在网页上">这不仅应用在网页上</h3> + +<p>值得注意的是并不是只有 JavaScript 使用事件——大多的编程语言都有这种机制,并且它们的工作方式不同于 JavaScript。实际上,JavaScript 网页上的事件机制不同于在其他环境中的事件机制。</p> + +<p>比如, <a href="/en-US/docs/Learn/Server-side/Express_Nodejs">Node.js</a> 是一种非常流行的允许开发者使用 JavaScript 来建造网络和服务器端应用的运行环境。<a href="https://nodejs.org/docs/latest-v5.x/api/events.html">Node.js event model</a> 依赖定期监听事件的监听器和定期处理事件的处理器——虽然听起来好像差不多,但是实现两者的代码是非常不同的,Node.js 使用像 on ( ) 这样的函数来注册一个事件监听器,使用 once ( ) 这样函数来注册一个在运行一次之后注销的监听器。 <a href="https://nodejs.org/docs/latest-v5.x/api/http.html#http_event_connect">HTTP connect event docs</a> 提供了很多例子。</p> + +<p>另外一个例子:您可以使用 JavaScript 来开发跨浏览器的插件(使用 <a href="/en-US/docs/Mozilla/Add-ons/WebExtensions">WebExtensions</a> 开发技术。事件模型和网站的事件模型是相似的,仅有一点点不同——事件监听属性是大驼峰的(如<code>onMessage</code>而不是<code>onmessage</code>),还需要与 <code>addListener</code> 函数结合, 参见 <a href="/en-US/Add-ons/WebExtensions/API/runtime/onMessage#Examples">runtime.onMessage page</a> 上的一个例子。</p> + +<p>您现在不需要掌握这些,我们只想表明不同的编程环境下事件机制是不同的,</p> + +<h2 id="使用网页事件的方式">使用网页事件的方式</h2> + +<p>您可以通过多种不同的方法将事件侦听器代码添加到网页,以便在关联的事件被触发时运行它。在本节中,我们将回顾不同的机制,并讨论应该使用哪些机制。</p> + +<h3 id="事件处理器属性">事件处理器属性</h3> + +<p><em>这些是我们的课程中最常见到的代码 - 存在于事件处理程序过程的属性中</em>。回到上面的例子:</p> + +<pre class="brush: js notranslate">const btn = document.querySelector('button'); + +btn.onclick = function() { + const rndCol = 'rgb(' + random(255) + ',' + random(255) + ',' + random(255) + ')'; + document.body.style.backgroundColor = rndCol; +}</pre> + +<p>这个 <code><a href="/en-US/docs/Web/API/GlobalEventHandlers/onclick">onclick</a></code> 是被用在这个情景下的事件处理器的属性,它就像 button 其他的属性(如 <code><a href="/en-US/docs/Web/API/Node/textContent">btn.textContent</a></code>, or <code><a href="/en-US/docs/Web/API/HTMLElement/style">btn.style</a></code>), 但是有一个特别的地方——当您将一些代码赋值给它的时候,只要事件触发代码就会运行。</p> + +<p>您也可以将一个有名字的函数赋值给事件处理参数(正如我们在 <a href="/en-US/docs/Learn/JavaScript/Building_blocks/Build_your_own_function">Build your own function</a> 中看到的),下面的代码也是这样工作的:</p> + +<pre class="brush: js notranslate">const btn = document.querySelector('button'); + +function bgChange() { + const rndCol = 'rgb(' + random(255) + ',' + random(255) + ',' + random(255) + ')'; + document.body.style.backgroundColor = rndCol; +} + +btn.onclick = bgChange;</pre> + +<p>有很多事件处理参数可供选择,我们来做一个实验。</p> + +<p>首先将 <a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/events/random-color-eventhandlerproperty.html">random-color-eventhandlerproperty.html</a> 复制到本地,然后用浏览器打开。别慌,这只是我们之前已经进行过的一个简单随机颜色的示例的代码复制。将 <code>btn.onclick</code> 依次换成其他值,在浏览器中观察效果。</p> + +<ul> + <li><code><a href="/en-US/docs/Web/API/GlobalEventHandlers/onfocus">btn.onfocus</a></code>及<code><a href="/en-US/docs/Web/API/GlobalEventHandlers/onblur">btn.onblur</a></code> — 颜色将于按钮被置于焦点或解除焦点时改变(尝试使用Tab移动至按钮上,然后再移开)。这些通常用于显示有关如何在置于焦点时填写表单字段的信息,或者如果表单字段刚刚填入不正确的值,则显示错误消息。</li> + <li><code><a href="/en-US/docs/Web/API/GlobalEventHandlers/ondblclick">btn.ondblclick</a></code> — 颜色将仅于按钮被双击时改变。</li> + <li><code><a href="/en-US/docs/Web/API/GlobalEventHandlers/onkeypress">window.onkeypress</a></code>, <code><a href="/en-US/docs/Web/API/GlobalEventHandlers/onkeydown">window.onkeydown</a></code>, <code><a href="/en-US/docs/Web/API/GlobalEventHandlers/onkeyup">window.onkeyup</a></code> — 当按钮被按下时颜色会发生改变. <code>keypress</code> 指的是通俗意义上的按下按钮 (按下并松开), 而 <code>keydown</code> 和 <code>keyup</code> 指的是按键动作的一部分,分别指按下和松开. 注意如果你将事件处理器添加到按钮本身,它将不会工作 — 我们只能将它添加到代表整个浏览器窗口的 <a href="/en-US/docs/Web/API/Window">window</a>对象中。</li> + <li><code><a href="/en-US/docs/Web/API/GlobalEventHandlers/onmouseover">btn.onmouseover</a></code> 和 <code><a href="/en-US/docs/Web/API/GlobalEventHandlers/onmouseout">btn.onmouseout</a></code> — 颜色将会在鼠标移入按钮上方时发生改变, 或者当它从按钮移出时.</li> +</ul> + +<p>一些事件非常通用,几乎在任何地方都可以用(比如 onclick 几乎可以用在几乎每一个元素上),然而另一些元素就只能在特定场景下使用,比如我们只能在 video 元素上使用 <a href="/en-US/docs/Web/API/GlobalEventHandlers/GlobalEventHandlers.onplay">onplay</a> 。</p> + +<h3 id="行内事件处理器_-_请勿使用">行内事件处理器 - 请勿使用</h3> + +<p>你也许在你的代码中看到过这么一种写法:</p> + +<pre class="brush: html notranslate"><button onclick="bgChange()">Press me</button> +</pre> + +<pre class="brush: js notranslate">function bgChange() { + const rndCol = 'rgb(' + random(255) + ',' + random(255) + ',' + random(255) + ')'; + document.body.style.backgroundColor = rndCol; +}</pre> + +<div class="note"> +<p><strong>Note</strong>: 您可以在<a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/events/random-color-eventhandlerattributes.html">GitHub</a>上找到这个示例的完整源代码(也可以<a href="http://mdn.github.io/learning-area/javascript/building-blocks/events/random-color-eventhandlerattributes.html">在线运行</a>).</p> +</div> + +<p>在Web上注册事件处理程序的最早方法是类似于上面所示的<strong>事件处理程序HTML属性</strong>(也称为内联事件处理程序)—属性值实际上是当事件发生时要运行的JavaScript代码。上面的例子中调用一个在{{htmlelement("script")}}元素在同一个页面上,但也可以直接在属性内插入JavaScript,例如:</p> + +<pre class="brush: html notranslate"><button onclick="alert('Hello, this is my old-fashioned event handler!');">Press me</button></pre> + +<p>你会发现HTML属性等价于对许多事件处理程序的属性;但是,你不应该使用这些 —— 他们被认为是不好的做法。使用一个事件处理属性似乎看起来很简单,如果你只是在做一些非常快的事情,但很快就变得难以管理和效率低下。</p> + +<p>一开始,您不应该混用 HTML 和 JavaScript,因为这样文档很难解析——最好的办法是只在一块地方写 JavaScript 代码。</p> + +<p>即使在单一文件中,内置事件处理器也不是一个好主意。一个按钮看起来还好,但是如果有一百个按钮呢?您得在文件中加上100个属性。这很快就会成为维护人员的噩梦。使用 Java Script,您可以给网页中的 button 都加上事件处理器。就像下面这样:</p> + +<pre class="brush: js notranslate">const buttons = document.querySelectorAll('button'); + +for (let i = 0; i < buttons.length; i++) { + buttons[i].onclick = bgChange; +}</pre> + +<div class="note"> +<p><strong>注释</strong>: 将您的编程逻辑与内容分离也会让您的站点对搜索引擎更加友好。</p> +</div> + +<h3 id="addEventListener_和removeEventListener">addEventListener() 和removeEventListener()</h3> + +<p>新的事件触发机制被定义在 <a href="https://www.w3.org/TR/DOM-Level-2-Events/">Document Object Model (DOM) Level 2 Events</a> Specification, 这个细则给浏览器提供了一个函数 — <code><a href="/en-US/docs/Web/API/EventTarget/addEventListener">addEventListener()</a></code>。这个函数和事件处理属性是类似的,但是语法略有不同。我们可以重写上面的随机颜色背景代码:</p> + +<pre class="brush: js notranslate">const btn = document.querySelector('button'); + +function bgChange() { + const rndCol = 'rgb(' + random(255) + ',' + random(255) + ',' + random(255) + ')'; + document.body.style.backgroundColor = rndCol; +} + +btn.addEventListener('click', bgChange);</pre> + +<div class="note"> +<p><strong>注释</strong>: 您可以在<a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/events/random-color-addeventlistener.html">Github</a>上找到这个示例的完整源代码(也可以<a href="http://mdn.github.io/learning-area/javascript/building-blocks/events/random-color-addeventlistener.html"> 在线运行</a>)。</p> +</div> + +<p><code>在addEventListener()</code> 函数中, 我们具体化了两个参数——我们想要将处理器应用上去的事件名称,和包含我们用来回应事件的函数的代码。注意将这些代码全部放到一个匿名函数中是可行的:</p> + +<pre class="brush: js notranslate">btn.addEventListener('click', function() { + var rndCol = 'rgb(' + random(255) + ',' + random(255) + ',' + random(255) + ')'; + document.body.style.backgroundColor = rndCol; +}); +</pre> + +<p>这个机制带来了一些相较于旧方式的优点。有一个相对应的方法,<code><a href="/en-US/docs/Web/API/EventTarget/removeEventListener">removeEventListener()</a>,</code>这个方法移除事件监听器。例如,下面的代码将会移除上个代码块中的事件监听器:</p> + +<pre class="brush: js notranslate">btn.removeEventListener('click', bgChange);</pre> + +<p>在这个简单的、小型的项目中可能不是很有用,但是在大型的、复杂的项目中就非常有用了,可以非常高效地清除不用的事件处理器,另外在其他的一些场景中也非常有效——比如您需要在不同环境下运行不同的事件处理器,您只需要恰当地删除或者添加事件处理器即可。</p> + +<p>您也可以给同一个监听器注册多个处理器,下面这种方式不能实现这一点:</p> + +<pre class="brush: js notranslate">myElement.onclick = functionA; +myElement.onclick = functionB;</pre> + +<p>第二行会覆盖第一行,但是下面这种方式就会正常工作了:</p> + +<pre class="brush: js notranslate">myElement.addEventListener('click', functionA); +myElement.addEventListener('click', functionB);</pre> + +<p>当元素被点击时两个函数都会工作:</p> + +<p>此外,该事件机制还提供了许多其他强大的特性和选项。这对于本文来说有点超出范围,但是如果您想要阅读它们,请查看<code><a href="https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener">addEventListener()</a></code>和<code><a href="https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/removeEventListener">removeEventListener()</a></code>参考页面。</p> + +<h3 id="我该使用哪种机制?">我该使用哪种机制?</h3> + +<p>在三种机制中,您绝对不应该使用HTML事件处理程序属性 - 这些属性已经过时了,而且也是不好的做法,如上所述.</p> + +<p>另外两种是相对可互换的,至少对于简单的用途:</p> + +<ul> + <li>事件处理程序属性功能和选项会更少,但是具有更好的跨浏览器兼容性(在Internet Explorer 8的支持下),您应该从这些开始学起。</li> + <li>DOM Level 2 Events (<code>addEventListener()</code>, etc.) 更强大,但也可以变得更加复杂,并且支持不足(只支持到Internet Explorer 9)。 但是您也应该尝试这个方法,并尽可能地使用它们。</li> +</ul> + +<p>第三种机制(DOM Level 2 Events (<code>addEventListener()</code>, etc.))的主要优点是,如果需要的话,可以使用<code>removeEventListener()</code>删除事件处理程序代码,而且如果有需要,您可以向同一类型的元素添加多个监听器。例如,您可以在一个元素上多次调用<code>addEventListener('click', function() { ... })</code>,并可在第二个参数中指定不同的函数。对于事件处理程序属性来说,这是不可能的,因为后面任何设置的属性都会尝试覆盖较早的属性,例如:</p> + +<pre class="brush: js notranslate">element.onclick = function1; +element.onclick = function2; +etc.</pre> + +<div class="note"> +<p><strong>注解</strong>:如果您在工作中被要求支持比Internet Explorer 8更老的浏览器,那么您可能会遇到困难,因为这些古老的浏览器会使用与现代浏览器不同的事件处理模型。但是不要害怕,大多数 JavaScript 库(例如 jQuery )都内置了能够跨浏览器差异的函数。在你学习 JavaScript 旅程里的这个阶段,不要太担心这个问题。</p> +</div> + +<h2 id="其他事件概念">其他事件概念</h2> + +<p>本节我们将简要介绍一些与事件相关的高级概念。在这一点并不需要完全理解透彻,但它可能有助于你解释一些经常会遇到的代码模式。</p> + +<h3 id="事件对象">事件对象</h3> + +<p>有时候在事件处理函数内部,您可能会看到一个固定指定名称的参数,例如<code>event</code>,<code>evt</code>或简单的<code>e</code>。 这被称为<strong>事件对象</strong>,它被自动传递给事件处理函数,以提供额外的功能和信息。 例如,让我们稍稍重写一遍我们的随机颜色示例:</p> + +<pre class="brush: js notranslate">function bgChange(e) { + const rndCol = 'rgb(' + random(255) + ',' + random(255) + ',' + random(255) + ')'; + e.target.style.backgroundColor = rndCol; + console.log(e); +} + +btn.addEventListener('click', bgChange);</pre> + +<div class="note"> +<p><strong>Note</strong>: 您可以在Github上查看这个示例的 <a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/events/random-color-eventobject.html">完整代码</a> ,或者在这里查看 <a href="http://mdn.github.io/learning-area/javascript/building-blocks/events/random-color-eventobject.html">实时演示</a>。</p> +</div> + +<p>在这里,您可以看到我们在函数中包括一个事件对象<code>e</code>,并在函数中设置背景颜色样式在<code>e.target上</code> - 它指的是按钮本身。 事件对象 <code>e</code> 的<code>target</code>属性始终是事件刚刚发生的元素的引用。 所以在这个例子中,我们在按钮上设置一个随机的背景颜色,而不是页面。</p> + +<div class="note"> +<p><strong>Note</strong>: 您可以使用任何您喜欢的名称作为事件对象 - 您只需要选择一个名称,然后可以在事件处理函数中引用它。 开发人员最常使用 e / evt / event,因为它们很简单易记。 坚持标准总是很好。</p> +</div> + +<p>当您要在多个元素上设置相同的事件处理程序时,<code>e.target</code>非常有用,并且在发生事件时对所有元素执行某些操作. 例如,你可能有一组16块方格,当它们被点击时就会消失。用e.target总是能准确选择当前操作的东西(方格)并执行操作让它消失,而不是必须以更困难的方式选择它。在下面的示例中(请参见<a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/events/useful-eventtarget.html">useful-eventtarget.html</a>完整代码;也可以在线运行<a href="http://mdn.github.io/learning-area/javascript/building-blocks/events/useful-eventtarget.html">running live</a>)我们使用JavaScript创建了16个<code><div></code>元素。接着我们使用 <code>document.querySelectorAll()</code>选择全部的元素,然后遍历每一个,为每一个元素都添加一个<code>onclick</code>单击事件,每当它们点击时就会为背景添加一个随机颜色。</p> + +<pre class="brush: js notranslate">const divs = document.querySelectorAll('div'); + +for (let i = 0; i < divs.length; i++) { + divs[i].onclick = function(e) { + e.target.style.backgroundColor = bgChange(); + } +}</pre> + +<p>输出如下(试着点击它-玩的开心):</p> + +<div class="hidden"> +<h6 id="Hidden_example">Hidden example</h6> + +<pre class="brush: html notranslate"><!DOCTYPE html> +<html> + <head> + <meta charset="utf-8"> + <title>Useful event target example</title> + <style> + div { + background-color: red; + height: 100px; + width: 25%; + float: left; + } + </style> + </head> + <body> + <script> + for (let i = 1; i <= 16; i++) { + const myDiv = document.createElement('div'); + document.body.appendChild(myDiv); + } + + function random(number) { + return Math.floor(Math.random()*number); + } + + function bgChange() { + var rndCol = 'rgb(' + random(255) + ',' + random(255) + ',' + random(255) + ')'; + return rndCol; + } + + const divs = document.querySelectorAll('div'); + + for (let i = 0; i < divs.length; i++) { + divs[i].onclick = function(e) { + e.target.style.backgroundColor = bgChange(); + } + } + </script> + </body> +</html></pre> +</div> + +<p>{{ EmbedLiveSample('Hidden_example', '100%', 400) }}</p> + +<p>你遇到的大多数事件处理器的事件对象都有可用的标准属性和函数(方法)(请参阅完整列表 <code>Event</code> 对象引用 )。然而,一些更高级的处理程序会添加一些专业属性,这些属性包含它们需要运行的额外数据。例如,媒体记录器API有一个<code>dataavailable</code>事件,它会在录制一些音频或视频时触发,并且可以用来做一些事情(例如保存它,或者回放)。对应的<code>ondataavailable</code>处理程序的事件对象有一个可用的数据属性。</p> + +<h3 id="阻止默认行为">阻止默认行为</h3> + +<p>有时,你会遇到一些情况,你希望事件不执行它的默认行为。 最常见的例子是Web表单,例如自定义注册表单。 当你填写详细信息并按提交按钮时,自然行为是将数据提交到服务器上的指定页面进行处理,并将浏览器重定向到某种“成功消息”页面(或 相同的页面,如果另一个没有指定。)</p> + +<p>当用户没有正确提交数据时,麻烦就来了 - 作为开发人员,你希望停止提交信息给服务器,并给他们一个错误提示,告诉他们什么做错了,以及需要做些什么来修正错误。 一些浏览器支持自动的表单数据验证功能,但由于许多浏览器不支持,因此建议你不要依赖这些功能,并实现自己的验证检查。 我们来看一个简单的例子。</p> + +<p>首先,一个简单的HTML表单,需要你填入名(first name)和姓(last name)</p> + +<pre class="brush: html notranslate"><form> + <div> + <label for="fname">First name: </label> + <input id="fname" type="text"> + </div> + <div> + <label for="lname">Last name: </label> + <input id="lname" type="text"> + </div> + <div> + <input id="submit" type="submit"> + </div> +</form> +<p></p></pre> + +<div class="hidden"> +<pre class="brush: css notranslate">div { + margin-bottom: 10px; +} +</pre> +</div> + +<p>这里我们用一个<code>onsubmit</code>事件处理程序(在提交的时候,在一个表单上发起<code>submit</code>事件)来实现一个非常简单的检查,用于测试文本字段是否为空。 如果是,我们在事件对象上调用<code>preventDefault()</code>函数,这样就停止了表单提交,然后在我们表单下面的段落中显示一条错误消息,告诉用户什么是错误的:</p> + +<pre class="brush: js notranslate">const form = document.querySelector('form'); +const fname = document.getElementById('fname'); +const lname = document.getElementById('lname'); +const submit = document.getElementById('submit'); +const para = document.querySelector('p'); + +form.onsubmit = function(e) { + if (fname.value === '' || lname.value === '') { + e.preventDefault(); + para.textContent = 'You need to fill in both names!'; + } +}</pre> + +<p>显然,这是一种非常弱的表单验证——例如,用户输入空格或数字提交表单,表单验证并不会阻止用户提交——这不是我们例子想要达到的目的。输出如下:</p> + +<p>{{ EmbedLiveSample('Preventing_default_behaviour', '100%', 140) }}</p> + +<div class="note"> +<p><strong>Note</strong>: 查看完整的源代码 <a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/events/preventdefault-validation.html">preventdefault-validation.html</a> (也可以 <a href="http://mdn.github.io/learning-area/javascript/building-blocks/events/preventdefault-validation.html">running live</a> )</p> +</div> + +<h3 id="事件冒泡及捕获">事件冒泡及捕获</h3> + +<p>最后即将介绍的这个主题你常常不会深究,但如果你不理解这个主题,就会十分痛苦。事件冒泡和捕捉是两种机制,主要描述当在一个元素上有两个相同类型的事件处理器被激活会发生什么。为了容易理解,我们来看一个例子——在新标签页打开这个<a href="http://mdn.github.io/learning-area/javascript/building-blocks/events/show-video-box.html">show-video-box.html</a> 例子(在这里可以查看源码 <a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/events/show-video-box.html">source code</a>)。也可以在下面查看:</p> + +<div class="hidden"> +<h6 id="Hidden_video_example">Hidden video example</h6> + +<pre class="brush: html notranslate"><!DOCTYPE html> +<html> + <head> + <meta charset="utf-8"> + <title>Show video box example</title> + <style> + div { + position: absolute; + top: 50%; + transform: translate(-50%,-50%); + width: 480px; + height: 380px; + border-radius: 10px; + background-color: #eee; + background-image: linear-gradient(to bottom, rgba(0,0,0,0), rgba(0,0,0,0.1)); + } + + .hidden { + left: -50%; + } + + .showing { + left: 50%; + } + + div video { + display: block; + width: 400px; + margin: 40px auto; + } + + </style> + </head> + <body> + <button>Display video</button> + + <div class="hidden"> + <video> + <source src="https://raw.githubusercontent.com/mdn/learning-area/master/javascript/building-blocks/events/rabbit320.mp4" type="video/mp4"> + <source src="https://raw.githubusercontent.com/mdn/learning-area/master/javascript/building-blocks/events/rabbit320.webm" type="video/webm"> + <p>Your browser doesn't support HTML5 video. Here is a <a href="rabbit320.mp4">link to the video</a> instead.</p> + </video> + </div> + + <script> + + const btn = document.querySelector('button'); + const videoBox = document.querySelector('div'); + const video = document.querySelector('video'); + + btn.onclick = function() { + displayVideo(); + } + + function displayVideo() { + if(videoBox.getAttribute('class') === 'hidden') { + videoBox.setAttribute('class','showing'); + } + } + + videoBox.addEventListener('click',function() { + videoBox.setAttribute('class','hidden'); + }); + + video.addEventListener('click',function() { + video.play(); + }); + + </script> + </body> +</html></pre> +</div> + +<p>{{ EmbedLiveSample('Hidden_video_example', '100%', 500) }}</p> + +<p>这是一个非常简单的例子,它显示和隐藏一个包含<code><video></code>元素的<code><div></code>元素:</p> + +<pre class="brush: html notranslate"><button>Display video</button> + +<div class="hidden"> + <video> + <source src="rabbit320.mp4" type="video/mp4"> + <source src="rabbit320.webm" type="video/webm"> + <p>Your browser doesn't support HTML5 video. Here is a <a href="rabbit320.mp4">link to the video</a> instead.</p> + </video> +</div></pre> + +<p>当‘’button‘’元素按钮被单击时,将显示视频,它是通过将改变<code><div>的</code>class属性值从<code>hidden</code>变为<code>showing</code>(这个例子的CSS包含两个<code>class</code>,它们分别控制这个<code><div></code>盒子在屏幕上显示还是隐藏。):</p> + +<pre class="brush: js notranslate">btn.onclick = function() { + videoBox.setAttribute('class', 'showing'); +}</pre> + +<p>然后我们再添加几个<code>onclick</code>事件处理器,第一个添加在<code><div></code>元素上,第二个添加在<code><video></code>元素上。这个想法是当视频(<code><video></code>)外 <code><div></code>元素内这块区域被单击时,这个视频盒子应该再次隐藏;当单击视频(<code><video></code>)本身,这个视频将开始播放。</p> + +<pre class="notranslate">videoBox.onclick = function() { + videoBox.setAttribute('class', 'hidden'); +}; + +video.onclick = function() { + video.play(); +};</pre> + +<p>但是有一个问题 - 当您点击<code>video</code>开始播放的视频时,它会在同一时间导致<code><div></code>也被隐藏。 这是因为<code>video</code>在<code><div></code>之内 - <code>video</code>是<code><div></code>的一个子元素 - 所以点击<code>video</code>实际上是同时也运行<code><div></code>上的事件处理程序。</p> + +<h4 id="对事件冒泡和捕捉的解释">对事件冒泡和捕捉的解释</h4> + +<p>当一个事件发生在具有父元素的元素上(例如,在我们的例子中是<code><video></code>元素)时,现代浏览器运行两个不同的阶段 - 捕获阶段和冒泡阶段。 在捕获阶段:</p> + +<ul> + <li>浏览器检查元素的最外层祖先<code><html></code>,是否在捕获阶段中注册了一个<code>onclick</code>事件处理程序,如果是,则运行它。</li> + <li>然后,它移动到<code><html></code>中单击元素的下一个祖先元素,并执行相同的操作,然后是单击元素再下一个祖先元素,依此类推,直到到达实际点击的元素。</li> +</ul> + +<p>在冒泡阶段,恰恰相反:</p> + +<ul> + <li>浏览器检查实际点击的元素是否在冒泡阶段中注册了一个<code>onclick</code>事件处理程序,如果是,则运行它</li> + <li>然后它移动到下一个直接的祖先元素,并做同样的事情,然后是下一个,等等,直到它到达<code><html></code>元素。</li> +</ul> + +<p><a href="https://mdn.mozillademos.org/files/14075/bubbling-capturing.png"><img alt="" src="https://mdn.mozillademos.org/files/14075/bubbling-capturing.png" style="display: block; height: 452px; margin: 0px auto; width: 960px;"></a></p> + +<p>(单击图片可以放大这个图表)</p> + +<p>在现代浏览器中,默认情况下,所有事件处理程序都在冒泡阶段进行注册。因此,在我们当前的示例中,当您单击视频时,这个单击事件从 <code><video></code>元素向外冒泡直到<code><html></code>元素。沿着这个事件冒泡线路:</p> + +<ul> + <li>它发现了<code>video.onclick...</code>事件处理器并且运行它,因此这个视频<code><video></code>第一次开始播放。</li> + <li>接着它发现了(往外冒泡找到的) <code>videoBox.onclick...</code>事件处理器并且运行它,因此这个视频<code><video></code>也隐藏起来了。</li> +</ul> + +<h4 id="用_stopPropagation_修复问题">用 stopPropagation() 修复问题</h4> + +<p>这是令人讨厌的行为,但有一种方法来解决它!标准事件对象具有可用的名为 <code><a href="/en-US/docs/Web/API/Event/stopPropagation">stopPropagation()</a></code>的函数, 当在事件对象上调用该函数时,它只会让当前事件处理程序运行,但事件不会在<strong>冒泡</strong>链上进一步扩大,因此将不会有更多事件处理器被运行(不会向上冒泡)。所以,我们可以通过改变前面代码块中的第二个处理函数来解决当前的问题:</p> + +<pre class="brush: js notranslate">video.onclick = function(e) { + e.stopPropagation(); + video.play(); +};</pre> + +<p>你可以尝试把 <a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/events/show-video-box.html">show-video-box.html source code</a> 拷贝到本地,然后自己动手修复它,或者在 <a href="http://mdn.github.io/learning-area/javascript/building-blocks/events/show-video-box-fixed.html">show-video-box-fixed.html</a> 页面查看修复结果(也可以在这里 <a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/events/show-video-box-fixed.html">source code</a> 查看源码)。</p> + +<div class="note"> +<p><strong>注解</strong>: 为什么我们要弄清楚捕捉和冒泡呢?那是因为,在过去糟糕的日子里,浏览器的兼容性比现在要小得多,Netscape(网景)只使用事件捕获,而Internet Explorer只使用事件冒泡。当W3C决定尝试规范这些行为并达成共识时,他们最终得到了包括这两种情况(捕捉和冒泡)的系统,最终被应用在现在浏览器里。</p> +</div> + +<div class="note"> +<p><strong>注解</strong>: 如上所述,默认情况下,所有事件处理程序都是在冒泡阶段注册的,这在大多数情况下更有意义。如果您真的想在捕获阶段注册一个事件,那么您可以通过使用<code><a href="https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener">addEventListener()</a></code>注册您的处理程序,并将可选的第三个属性设置为true。</p> +</div> + +<h4 id="事件委托">事件委托</h4> + +<p>冒泡还允许我们利用事件委托——这个概念依赖于这样一个事实,如果你想要在大量子元素中单击任何一个都可以运行一段代码,您可以将事件监听器设置在其父节点上,并让子节点上发生的事件冒泡到父节点上,而不是每个子节点单独设置事件监听器。</p> + +<p>一个很好的例子是一系列列表项,如果你想让每个列表项被点击时弹出一条信息,您可以将<code>click</code>单击事件监听器设置在父元素<code><ul></code>上,这样事件就会从列表项冒泡到其父元素<code><ul></code>上。</p> + +<p>这个的概念在David Walsh的博客上有更多的解释,并有多个例子——看看<a href="https://davidwalsh.name/event-delegate">How JavaScript Event Delegation Works</a>.</p> + +<h2 id="结论">结论</h2> + +<p>现在您应该知道在这个早期阶段您需要了解的所有web事件。如上所述,事件并不是JavaScript的核心部分——它们是在浏览器Web APIs中定义的。</p> + +<p>另外,理解JavaScript在不同环境下使用不同的事件模型很重要——从Web api到其他领域,如浏览器WebExtensions和Node.js(服务器端JavaScript)。我们并不期望您现在了解所有这些领域,但是当您在学习web开发的过程中,理解这些事件的基础是很有帮助的。</p> + +<p>如果你有什么不明白的地方,请重新阅读这篇文章,或者联系<a href="https://developer.mozilla.org/en-US/Learn#Contact_us">contact us</a>我们寻求帮助。</p> + +<h2 id="参见">参见</h2> + +<ul> + <li><a href="http://www.quirksmode.org/js/events_order.html">Event order</a> (discussion of capturing and bubbling) — an excellently detailed piece by Peter-Paul Koch.</li> + <li><a href="http://www.quirksmode.org/js/events_access.html">Event accessing</a> (discussing of the event object) — another excellently detailed piece by Peter-Paul Koch.</li> + <li><a href="/en-US/docs/Web/Events">Event reference</a></li> +</ul> + +<p>{{PreviousMenuNext("Learn/JavaScript/Building_blocks/Return_values","Learn/JavaScript/Building_blocks/Image_gallery", "Learn/JavaScript/Building_blocks")}}</p> diff --git a/files/zh-cn/learn/javascript/building_blocks/functions/index.html b/files/zh-cn/learn/javascript/building_blocks/functions/index.html new file mode 100644 index 0000000000..a4cdc2c0c2 --- /dev/null +++ b/files/zh-cn/learn/javascript/building_blocks/functions/index.html @@ -0,0 +1,428 @@ +--- +title: 函数-可复用代码块 +slug: learn/JavaScript/Building_blocks/Functions +tags: + - API + - JavaScript + - 函数 + - 初学者 + - 匿名 + - 参数 + - 学习 + - 方法 + - 浏览器 + - 自定义 +translation_of: Learn/JavaScript/Building_blocks/Functions +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/JavaScript/Building_blocks/Looping_code","Learn/JavaScript/Building_blocks/Build_your_own_function", "Learn/JavaScript/Building_blocks")}}</div> + +<p class="summary">在JavaScript中另一个基本概念是<strong>函数</strong>, 它允许你在一个代码块中存储一段用于处理单任务的代码,然后在任何你需要的时候用一个简短的命令来调用,而不是把相同的代码写很多次。在本文中,我们将探索函数的基本概念,如基本语法、如何定义和调用、范围和参数。</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">前提条件:</th> + <td>基本的电脑知识,对HTML与CSS有基本的了解,及已阅读: <a href="https://developer.mozilla.org/en-US/docs/Learn/JavaScript/First_steps">JavaScript first steps</a>(JS的入门)。</td> + </tr> + <tr> + <th scope="row">目标:</th> + <td>了解 Javascript 函数背后的基本概念。</td> + </tr> + </tbody> +</table> + +<h2 id="我能在哪找到函数">我能在哪找到函数?</h2> + +<p>在 JavaScript中, 你将发现函数无处不在 。事实上, 到目前为止,我们一直在使用函数,只是我们还没很好的讨论它们。然而现在是时候了,让我们开始聊聊函数,并探索它们的语法。</p> + +<p>几乎任何时候,只要你使用一个带有一对圆括号()的JavaScript结构,并且你不是在使用一个常见的比如for for循环,while或do…while循环,或者if语句这样的内置语言结构时,那么您就正在使用函数。</p> + +<div class="hidden"></div> + +<h2 id="浏览器内置函数">浏览器内置函数</h2> + +<p>在这套课程中我们已经使用了很多浏览器内置函数,当我们操作一个字符串的时候,例如:</p> + +<pre class="brush: js notranslate">var myText = 'I am a string'; +var newString = myText.replace('string', 'sausage'); +console.log(newString); +// the replace() string function takes a string, +// replaces one substring with another, and returns +// a new string with the replacement made</pre> + +<p>或者当我们操作一个数组的时候:</p> + +<pre class="brush: js notranslate">var myArray = ['I', 'love', 'chocolate', 'frogs']; +var madeAString = myArray.join(' '); +console.log(madeAString); +// the join() function takes an array, joins +// all the array items together into a single +// string, and returns this new string</pre> + +<p>或者当我们生成一个随机数时:</p> + +<pre class="brush: js notranslate">var myNumber = Math.random() +// the random() function generates a random +// number between 0 and 1, and returns that +// number</pre> + +<p>...我们已经使用过函数了!</p> + +<div class="note"> +<p>提示:如果需要,你可以随意将这些代码输入浏览器控制台以便于你熟悉其功能。</p> +</div> + +<p>JavaScript有许多内置的函数<span style="">,可以让您做很多有用的事情,而无需自己编写所有的代码。事实上</span>, 许多你调用(运行或者执行的专业词语)浏览器内置函数时调用的代码并不是使用JavaScript来编写——大多数调用浏览器后台的函数的代码,是使用像C++这样更低级的系统语言编写的,而不是像JavaScript这样的web编程语言。</p> + +<p>请记住,这些内置浏览器函数不是核心JavaScript语言的一部分——被定义为浏览器API的一部分,它建立在默认语言之上,以提供更多的功能(请参阅本课程的早期部分以获得更多的描述)。我们将在以后的模块中更详细地使用浏览器API。</p> + +<h2 id="函数与方法">函数与方法</h2> + +<p>程序员把函数称为对象<strong>方法(method)</strong>的一部分。你还不必了解JavaScript中已建构的对象在更深层次上是如何运作的<font><font>——你可以等到下一小节,我们会教给你有关对象运作方式的一切。</font></font><font><font>在我们继续前进之前,我们需要澄清一些有关方法和函数概念之间可能存在的误会——当你在网络上浏览相关信息的时候,你很可能会碰上这两个术语。</font></font></p> + +<p>到目前为止我们所使用的内置代码同属于这两种形式:函数和方法。你可以在<a href="/zh-CN/docs/Web/JavaScript/Reference/Global_Objects">这里</a>查看内置函数,内置对象以及其相关方法的完整列表。</p> + +<p><font><font>严格说来,内置浏览器函数并不是函数——它们是</font></font><strong style=""><font><font>方法</font></font></strong><font><font>。</font><font>这听起来有点可怕和令人困惑,但不要担心 ——函数和方法在很大程度上是可互换的,</font></font>至少在我们的学习阶段是这样的<font><font>。</font></font></p> + +<p>二者区别在于方法是在对象内定义的函数。浏览器内置函数(方法)和变量(称为属性)存储在结构化对象内,以使代码更加高效,易于处理。</p> + +<div class="hidden"></div> + +<h2 id="自定义函数">自定义函数</h2> + +<p>您在过去的课程中还看到很多定制功能 - 在代码中定义的功能,而不是在浏览器中。每当您看到一个自定义名称后面都带有括号,那么您使用的是自定义函数. <font><font>在我们</font><font>的</font><a href="https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Building_blocks/Looping_code"><font>循环文章中</font></a><font>的</font></font><a href="http://mdn.github.io/learning-area/javascript/building-blocks/loops/random-canvas-circles.html"><font><font>random-canvas-circles.html</font></font></a><font><font>示例(另见完整的</font></font><a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/loops/random-canvas-circles.html"><font><font>源代码</font></font></a><font><font>)中</font><font>,我们包括一个如下所示的自定义</font><font>函数:</font></font><code>draw()</code></p> + +<pre class="brush: js notranslate">function draw() { + ctx.clearRect(0,0,WIDTH,HEIGHT); + for (var i = 0; i < 100; i++) { + ctx.beginPath(); + ctx.fillStyle = 'rgba(255,0,0,0.5)'; + ctx.arc(random(WIDTH), random(HEIGHT), random(50), 0, 2 * Math.PI); + ctx.fill(); + } +}</pre> + +<p><font><font>该函数在</font></font><a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/canvas" title="使用HTML <canvas>元素与canvas脚本API来绘制图形和动画。"><code><canvas></code></a><font><font>元素中</font><font>绘制100个随机圆</font><font>。</font><font>每次我们想要这样做,我们可以使用这个函数来调用这个功能</font></font></p> + +<pre class="brush: js notranslate">draw();</pre> + +<p><font><font>而不是每次我们想重复一遍,都要写出所有的代码。</font><font>函数可以包含任何您喜欢的代码 - 甚至可以从内部函数调用其他函数。</font><font>以上函数例如调用</font></font><code>random()</code><font><font>函数三次,由以下代码定义:</font></font></p> + +<pre class="brush: js notranslate">function random(number) { + return Math.floor(Math.random()*number); +}</pre> + +<p><font><font>我们需要这个函数,因为浏览器的内置</font></font><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/random"><font><font>Math.random()</font></font></a><font><font>函数只生成一个0到1之间的随机十进制数。我们想要一个0到一个指定数字之间的随机整数。</font></font></p> + +<div class="hidden"></div> + +<h2 id="调用函数">调用函数</h2> + +<p>现在你可能很清楚这一点,<font>但仅仅为了防止……,要在函数定义之后,实际使用它,你必须运行或调用它。</font><font>这是通过将函数名包含在代码的某个地方,后跟圆括号来完成的。</font></p> + +<pre class="brush: js notranslate">function myFunction() { + alert('hello'); +} + +myFunction() +// calls the function once</pre> + +<h2 id="匿名函数">匿名函数</h2> + +<p><font>您可能会以稍微不同的方式看到定义和调用的函数。</font><font>到目前为止,我们刚刚创建了如下函数:</font></p> + +<pre class="brush: js notranslate">function myFunction() { + alert('hello'); +}</pre> + +<p>但是您也可以创建一个没有名称的函数:</p> + +<pre class="brush: js notranslate">function() { + alert('hello'); +}</pre> + +<p>这个函数叫做<strong>匿名函数</strong> — 它没有函数名! 它也不会自己做任何事情。 你通常将匿名函数与事件处理程序一起使用, 例如,如果单击相关按钮,以下操作将在函数内运行代码:</p> + +<pre class="brush: js notranslate">var myButton = document.querySelector('button'); + +myButton.onclick = function() { + alert('hello'); +}</pre> + +<p>上述示例将要求{{htmlelement("button")}} <font>在页面上提供可用于选择并单击</font><font>的</font><font>元素。</font><font>您在整个课程中已经看到过这种结构了几次,您将在下一篇文章中了解更多信息并在其中使用。</font></p> + +<p>你还可以将匿名函数分配为变量的值,例如:</p> + +<pre class="brush: js notranslate">var myGreeting = function() { + alert('hello'); +}</pre> + +<p>现在可以使用以下方式调用此函数:</p> + +<pre class="brush: js notranslate">myGreeting();</pre> + +<p>有效地给变量一个名字;还可以将该函数分配为多个变量的值,例如:</p> + +<pre class="brush: js notranslate">var anotherGreeting = function() { + alert('hello'); +}</pre> + +<p>现在可以使用以下任一方法调用此函数</p> + +<pre class="brush: js notranslate">myGreeting(); +anotherGreeting();</pre> + +<p>但这只会令人费解,所以不要这样做!创建方法时,最好坚持下列形式:</p> + +<pre class="brush: js notranslate">function myGreeting() { + alert('hello'); +}</pre> + +<p>您将主要使用匿名函数来运行负载的代码以响应事件触发(如点击按钮) - 使用事件处理程序。再次,这看起来像这样:</p> + +<pre class="brush: js notranslate">myButton.onclick = function() { + alert('hello'); + // I can put as much code + // inside here as I want +}</pre> + +<div class="note"> +<p>匿名函数也称为函数表达式。函数表达式与函数声明有一些区别。函数声明会进行声明提升(declaration hoisting),而函数表达式不会。</p> +</div> + +<h2 id="函数参数">函数参数</h2> + +<p>一些函数需要在调用它们时指定参数 ——这些参数值需要放在函数括号内,才能正确地完成其工作。</p> + +<div class="note"> +<p><strong>Note</strong>: 参数有时称为参数(arguments),属性(properties)或甚至属性(attributes)</p> +</div> + +<p><font><font>例如,浏览器的内置</font></font><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/random"><font><font>Math.random()</font></font></a><font><font>函数不需要任何参数。</font><font>当被调用时,它总是返回0到1之间的随机数:</font></font></p> + +<pre class="brush: js notranslate">var myNumber = Math.random();</pre> + +<p><font><font>浏览器的内置字符串</font></font><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/replace"><font><font>replace()</font></font></a><font><font>函数需要两个参数:在主字符串中查找的子字符串,以及用以下替换该字符串的子字符串:</font></font></p> + +<pre class="brush: js notranslate">var myText = 'I am a string'; +var newString = myText.replace('string', 'sausage');</pre> + +<div class="note"> +<p><strong>Note</strong>:当您需要指定多个参数时,它们以逗号分隔。</p> +</div> + +<p><font><font>还应该注意,有时参数不是必须的 </font></font>—— <font><font>您不必指定它们。</font><font>如果没有,该功能一般会采用某种默认行为。</font><font>作为示例,数组 </font></font><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/join"><font><font>join()</font></font></a><font><font>函数的参数是可选的:</font></font></p> + +<pre class="brush: js notranslate">var myArray = ['I', 'love', 'chocolate', 'frogs']; +var madeAString = myArray.join(' '); +// returns 'I love chocolate frogs' +var madeAString = myArray.join(); +// returns 'I,love,chocolate,frogs'</pre> + +<p>如果没有包含参数来指定加入/分隔符,默认情况下会使用逗号</p> + +<div class="hidden"></div> + +<h2 id="函数作用域和冲突">函数作用域和冲突</h2> + +<p>我们来谈一谈 {{glossary("scope")}}即作用域 — 处理函数时一个非常重要的概念。当你创建一个函数时,函数内定义的变量和其他东西都在它们自己的单独的范围内, 意味着它们被锁在自己独立的隔间中, 不能被函数外的代码访问。</p> + +<p>所有函数的最外层被称为全局作用域。 在全局作用域内定义的值可以在任意地方访问。</p> + +<p><font>JavaScript由于各种原因而建立,但主要是由于安全性和组织性。</font><font>有时您不希望变量可以在代码中的任何地方访问 - 您从其他地方调用的外部脚本可能会开始搞乱您的代码并导致问题,因为它们恰好与代码的其他部分使用了相同的变量名称,造成冲突。</font><font>这可能是恶意的,或者是偶然的。</font></p> + +<div class="hidden"></div> + +<p>例如,假设您有一个HTML文件,它调用两个外部JavaScript文件,并且它们都有一个使用相同名称定义的变量和函数:</p> + +<pre class="brush: html notranslate"><!-- Excerpt from my HTML --> +<script src="first.js"></script> +<script src="second.js"></script> +<script> + greeting(); +</script></pre> + +<pre class="brush: js notranslate">// first.js +var name = 'Chris'; +function greeting() { + alert('Hello ' + name + ': welcome to our company.'); +}</pre> + +<pre class="brush: js notranslate">// second.js +var name = 'Zaptec'; +function greeting() { + alert('Our company is called ' + name + '.'); +}</pre> + +<p><font><font>这两个函数都使用 </font></font><code>greeting()</code><font><font> 形式调用,但是你只能访问到 <font face="consolas, Liberation Mono, courier, monospace"><span style="">first.js</span></font> 文件的</font></font><code>greeting()</code><font><font>函数(第二个文件被忽视了)。另外,第二次尝试使用 <code>let</code> 关键字定义 <code>name</code> 变量导致了一个错误。</font></font></p> + +<div class="note"> +<p><strong>Note</strong>: 您可以参考这个例子 <a href="http://mdn.github.io/learning-area/javascript/building-blocks/functions/conflict.html">running live on GitHub</a> (查看完整 <a href="https://github.com/mdn/learning-area/tree/master/javascript/building-blocks/functions">源代码</a>).</p> +</div> + +<p>将代码锁定在函数中的部分避免了这样的问题,并被认为是最佳实践。</p> + +<p><font>这有点像一个动物园。</font><font>狮子,斑马,老虎和企鹅都保留在自己的园子中,只能拿到到它们园子中的东西 —— 与其函数作用域相同。</font><font>如果他们能进入其他园子,就会出现问题。不同的动物会在不熟悉的栖息地内感到真的不舒服 - 一只狮子或老虎会在企鹅的水多的,冰冷的的领域中感到可怕。最糟糕的是,狮子和老虎可能会尝试吃企鹅!</font></p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/14079/MDN-mozilla-zoo.png" style="display: block; margin: 0 auto;"></p> + +<p>动物园管理员就像全局作用域 - 他或她有钥匙访问每个园子,重新投喂食物,照顾生病的动物等。</p> + +<h3 id="主动学习_和_scope_玩耍">主动学习: 和 scope 玩耍</h3> + +<p>我们来看一个真正的例子来展示范围</p> + +<ol> + <li><font><font>首先,制作我们的</font></font><a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/functions/function-scope.html"><font><font>function-scope.html</font></font></a><font><font>示例</font><font>的本地副本</font><font>。它</font><font>包含两个函数</font></font><code>a()</code><font><font>和</font></font><code>b()</code><font><font>,和三个变量—— </font></font><code>x</code><font><font>,</font></font><code>y</code><font><font>和</font></font><code>z</code><font><font>——其中两个在函数中被定义,另一个被定义在全局作用域内。</font><font>它还包含一个名为</font></font><code>output()</code>的函数<font><font>,它接收一个参数,并将其输出到页面的一个段落中。</font></font></li> + <li><font><font>在浏览器和文本编辑器中打开示例。</font></font></li> + <li><font><font>在浏览器开发工具中打开JavaScript控制台。</font><font>在JavaScript控制台中,输入以下命令:</font></font></li> +</ol> + +<pre class="brush: js notranslate">output(x);</pre> + +<p><font><font>您应该看到变量</font></font><code>x</code><font><font>输出到屏幕</font><font>的值</font><font>。</font></font></p> + +<p> 4.现在尝试在您的控制台中输入以下内容</p> + +<pre class="brush: js notranslate">output(y); +output(z);</pre> + +<p><font><font>这两个都应该返回错误沿“ </font></font><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Errors/Not_defined"><font><font>ReferenceError:y未定义</font></font></a><font><font> ”。</font><font>这是为什么?</font><font>由于函数作用域 - </font></font><code>y<font face="Open Sans, arial, x-locale-body, sans-serif"><span style="">和</span></font></code><code>z</code>被<font><font>锁定在</font><font>函数</font></font><code>a()</code><font><font>和</font></font><code>b()</code><font><font>函数中,所以</font></font><code>output()</code><font><font>从全局作用域调用时无法访问它们。</font></font></p> + +<p><font><font> 5.但是,从另一个函数里面调用什么呢?</font><font>尝试编辑</font></font><code>a()</code><font><font>,</font></font><code>b()</code><font><font>所以他们看起来像这样:</font></font></p> + +<pre class="brush: js notranslate">function a() { + var y = 2; + output(y); +} + +function b() { + var z = 3; + output(z); +}</pre> + +<p><font><font>保存代码并重新加载到浏览器中,然后尝试</font><font>从JavaScript控制台</font><font>调用</font></font><code>a()</code><font><font>和</font></font><code>b()</code><font><font>函数:</font></font></p> + +<pre class="brush: js notranslate">a(); +b();</pre> + +<p><font><font>您应该看到</font><font>页面中输出的</font></font><code>y</code><font><font>和</font></font><code>z</code>的<font><font>值。</font><font>这样就没问题,因为</font></font><code>output()</code><font><font>函数在其他函数的内部被调用 - 在这种情况下,输出变量的定义和函数的调用都在同一个作用域中(译者注:即函数作用域)。</font></font><code>output()</code><font><font>它可以从任何地方被调用,因为它在全局作用域中被定义。</font></font></p> + +<p> 6.现在尝试更新您的代码,如下所示:</p> + +<pre class="brush: js notranslate">function a() { + var y = 2; + output(x); +} + +function b() { + var z = 3; + output(x); +}</pre> + +<p>再次保存并重新加载,并在JavaScript控制台中再次尝试:</p> + +<pre class="brush: js notranslate">a(); +b();</pre> + +<p><font><font>函数 </font></font><code>a()</code><font><font>和</font></font><code>b()</code><font><font>都应该输出x---1的值。这些没有问题,因为即使</font></font><code>output()</code>的<font><font>调用与</font></font><code>x</code>的<font><font>定义</font><font>不在同一个作用域内</font><font>,但</font></font><code>x</code><font><font>是一个全局变量,所以在所有代码中都可用。</font></font></p> + +<p>7.最后,尝试更新您的代码,如下所示:</p> + +<pre class="brush: js notranslate">function a() { + var y = 2; + output(z); +} + +function b() { + var z = 3; + output(y); +}</pre> + +<p>再次保存并重新加载,并在JavaScript控制台中再次尝试:</p> + +<pre class="brush: js notranslate">a(); +b();</pre> + +<p><font><font>这次</font></font><code>a()</code><font><font>和</font></font><code>b()</code><font><font>调用都会返回那个令人讨厌的</font></font> "<a href="/en-US/docs/Web/JavaScript/Reference/Errors/Not_defined">ReferenceError: z is not defined</a>" error — 这是因为<code>output()</code>函数的调用和输出变量的定义不在同一个函数作用域内 - 变量对这些函数调用是不可见的。</p> + +<div class="note"> +<p><strong>注意</strong>:相同的范围规则不适用于循环(for(){...})和条件块(if(){...}) - 它们看起来非常相似,但它们不一样!小心不要让这些困惑。</p> +</div> + +<div class="note"> +<p>注意:ReferenceError:“x”未定义错误是您遇到的最常见的错误。如果您收到此错误,并且确定您已经定义了该问题的变量,请检查它的范围。</p> +</div> + +<ul> +</ul> + +<h3 id="函数内部的函数">函数内部的函数</h3> + +<p><font>请记住,您可以从任何地方调用函数,甚至可以在另一个函数中调用函数。</font><font>这通常被用作保持代码整洁的方式 - 如果您有一个复杂的函数,如果将其分解成几个子函数,它更容易理解:</font></p> + +<pre class="brush: js notranslate">function myBigFunction() { + var myValue; + + subFunction1(); + subFunction2(); + subFunction3(); +} + +function subFunction1() { + console.log(myValue); +} + +function subFunction2() { + console.log(myValue); +} + +function subFunction3() { + console.log(myValue); +} +</pre> + +<p>要确保函数调取的数值处在有效的作用域内。上面的例子中会产生一个错误提示,<code>ReferenceError:myValue is not define</code>,因为尽管<code>myValue</code>变量与函数调用指令处在同一个作用域中, 但它却没有在函数内被定义 <font><font>——</font></font> 实际代码在调用函数时就开始运行了。为了使代码正确运作,你必须将值作为参数传递给函数,如下所示:</p> + +<pre class="brush: js notranslate">function myBigFunction() { + var myValue = 1; + + subFunction1(myValue); + subFunction2(myValue); + subFunction3(myValue); +} + +function subFunction1(value) { + console.log(value); +} + +function subFunction2(value) { + console.log(value); +} + +function subFunction3(value) { + console.log(value); +}</pre> + +<h2 id="测试你的技能!"><font face="x-locale-heading-primary, zillaslab, Palatino, Palatino Linotype, x-locale-heading-secondary, serif"><span style="font-size: 37.33327865600586px;"><strong>测试你的技能!</strong></span></font></h2> + +<p>你已经来到了本文章的结尾,但是你还能记得最重要的知识吗?你可以在离开这里找到一些更深度的测试来证实你已经记住了这些知识——查看<a href="https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Building_blocks/Test_your_skills:_Functions">测试你的技能:函数</a>(英文)。后两章文本包含了这个测试需要的技能,所以你可能先需要阅读再尝试该测试。</p> + +<h2 id="总结">总结</h2> + +<p>本文探讨了函数背后的基本概念,为之后的学习奠定了基础。下一步,我们将进行实践,并带你一步步建立起你自己的函数。</p> + +<h2 id="参见">参见</h2> + +<ul> + <li><a href="/en-US/docs/Web/JavaScript/Guide/Functions">Functions detailed guide</a> — covers some advanced features not included here.</li> + <li><a href="/en-US/docs/Web/JavaScript/Reference/Functions">Functions reference</a></li> + <li><a href="/en-US/docs/Web/JavaScript/Reference/Functions/Default_parameters">Default parameters</a>, <a href="/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions">Arrow functions</a> — advanced concept references</li> +</ul> + +<ul> +</ul> + +<p>{{PreviousMenuNext("Learn/JavaScript/Building_blocks/Looping_code","Learn/JavaScript/Building_blocks/Build_your_own_function", "Learn/JavaScript/Building_blocks")}}</p> diff --git a/files/zh-cn/learn/javascript/building_blocks/index.html b/files/zh-cn/learn/javascript/building_blocks/index.html new file mode 100644 index 0000000000..0f6f3798d2 --- /dev/null +++ b/files/zh-cn/learn/javascript/building_blocks/index.html @@ -0,0 +1,55 @@ +--- +title: 创建JavaScript代码块 +slug: learn/JavaScript/Building_blocks +tags: + - JavaScript + - 事件 + - 优先级 + - 函数 + - 循环 + - 教程 + - 文章 + - 新手 + - 条件 + - 模块 + - 编码 + - 评估 +translation_of: Learn/JavaScript/Building_blocks +--- +<div>{{LearnSidebar}}</div> + +<p class="summary">在这个模块中, 我们将继续介绍JavaScript的关键基本特性,在这一章中我们将关注条件控制语句、循环语句、函数模块、事件等通用代码块。你可能在之前的的课程中见过这些模块,但仅仅是见过—在这篇模块中我们将明确讨论这些模块.</p> + +<h2 id="预备知识">预备知识</h2> + +<p>在开始这部分模块之前, 你应该熟悉基本的HTML和CSS, 并且已经看完我们之前的模块:<a href="/zh-CN/docs/Learn/JavaScript/First_steps">JavaScript 第一步</a>。</p> + +<div class="note"> +<p><strong>注</strong>: 如果你在使用无法创建自己文件的电脑/平板/其他设备,你可以试试在线编辑器,例如 <a href="http://jsbin.com/">JSBin</a> 或 <a href="https://thimble.mozilla.org/">Thimble</a>.</p> +</div> + +<h2 id="指南">指南</h2> + +<dl> + <dt><a href="/zh-CN/docs/Learn/JavaScript/Building_blocks/conditionals">在代码中做决定 — 条件</a></dt> + <dd>在任何程序语言中,程序需要根据不同的输入数据作出相应的选择并执行相关的操作。例如,在游戏中,如果玩家的生命值是0,那么游戏就结束了。在天气应用中,如果在早上打开应用,则显示一个太阳升起的图片,如果在晚上打开,则显示星星和月亮。在这篇文章里我们将探索如何在JS中使用条件结构。</dd> + <dt><a href="/zh-CN/docs/Learn/JavaScript/Building_blocks/Looping_code">循环语句</a></dt> + <dd>有时候你需要在一个行中重复执行某一个任务。例如,查看一整列的名字。在程序中,循环能非常好的处理好这个问题。在本章中我们将介绍JavaScript的循环语句。</dd> + <dt><a href="/zh-CN/docs/Learn/JavaScript/Building_blocks/Functions">函数 — 可重用的代码块</a></dt> + <dd>在编码中的另一个基本概念是函数(functions)。 <strong>函数</strong> 允许你在定义的区块内存储一段代码用来执行一个单独的任务,然后调用该段代码时,你需要使用一个简短的命令,而不用重复编写多次该段代码。在这篇文章中我们将探讨函数的基本概念,如语法、如何调用定义的函数、作用域和参数。</dd> + <dt><a href="/zh-CN/docs/Learn/JavaScript/Building_blocks/Build_your_own_function">打造自己的函数</a></dt> + <dd>本文结合前几篇文章中所涉及的基本理论,提供了一个实践经验。在这里你会得到一些实践,并且编写自己的自定义函数。随后,我们也将进一步解释一些与函数相关的有用的细节。</dd> + <dt><a href="/zh-CN/docs/Learn/JavaScript/Building_blocks/Return_values">函数返回值</a></dt> + <dd>在这个课程中,我们要讨论的最后一个基本概念是返回值(通过返回值结束我们的函数)。有些函数在完成后不返回任何值,而有些函数返回。重要的是了解返回的值是什么,和如何在你的代码中使用他们,以及如何使自定义的函数返回需要的值。</dd> + <dt><a href="/zh-CN/docs/Learn/JavaScript/Building_blocks/Events">事件介绍</a></dt> + <dd>事件是你正在编写的系统中发生的动作或事件,系统告诉你的是这些动作或事件,如果需要的话,你可以以某种方式对它们做出反应。例如,如果用户单击网页上的按钮,您可能希望通过显示信息框来响应该操作。在这最后一篇文章中,我们将重点讨论一些围绕事件有关的概念,看看他们如何在浏览器中工作。</dd> +</dl> + +<h2 id="评估">评估</h2> + +<p>下面的评估将测试您对JavaScript基础知识的理解。</p> + +<dl> + <dt><a href="https://developer.mozilla.org/zh-CN/docs/Learn/JavaScript/Building_blocks/Image_gallery">图片画廊</a></dt> + <dd>现在我们已经学习了构建JavaScript的基本代码块,我们会通过构建一个在很多网站上相当常见的项目——一个由JavaScript驱动的相册,来测试你循环、函数、条件语句和事件方面的知识。</dd> +</dl> diff --git a/files/zh-cn/learn/javascript/building_blocks/looping_code/index.html b/files/zh-cn/learn/javascript/building_blocks/looping_code/index.html new file mode 100644 index 0000000000..3fb1a217da --- /dev/null +++ b/files/zh-cn/learn/javascript/building_blocks/looping_code/index.html @@ -0,0 +1,781 @@ +--- +title: 循环吧代码 +slug: learn/JavaScript/Building_blocks/Looping_code +tags: + - JavaScript + - break + - continue + - for + - while + - 初学者 + - 学习 + - 循环 +translation_of: Learn/JavaScript/Building_blocks/Looping_code +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/JavaScript/Building_blocks/conditionals","Learn/JavaScript/Building_blocks/Functions", "Learn/JavaScript/Building_blocks")}}</div> + +<p class="summary">编程语言可以很迅速方便地帮我们完成一些重复性的任务,<font>从多个基本计算到几乎完成了很多类似工作的其他情况。现在</font><font>我们来看看处理这种需求的JavaScript中可用的循环结构。</font></p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">前提条件:</th> + <td>基本的电脑知识,对HTML与CSS有基本的了解,及已阅读: <a href="/en-US/docs/Learn/JavaScript/First_steps">JavaScript first steps</a>(JS的入门).</td> + </tr> + <tr> + <th scope="row">目标:</th> + <td>学习如何在JS里面使用循环语句.</td> + </tr> + </tbody> +</table> + +<h2 id="来一起循环">来一起循环</h2> + +<p>循环,循环,循环. 就与这些:<a href="https://en.wikipedia.org/wiki/Froot_Loops">popular breakfast cereals</a>, <a href="https://en.wikipedia.org/wiki/Vertical_loop">roller coasters</a> and <a href="https://en.wikipedia.org/wiki/Loop_(music)">musical production</a>一样,类似存在于编程中.编程中的循环也是一直重复着去做一件事 - 此处循环便是编程中的术语.</p> + +<p>让我们来想一下下图,这位农夫考虑为他的家庭做一周的食物计划,他或许就需要执行一段循环:</p> + +<p><img alt="" src="https://raw.githubusercontent.com/agnoCJY/agno.github.io/master/loop_js-02-farm-cn.png" style="height: 563px; width: 900px;"><br> + </p> + +<p>一段循环通常需要一个或多个条件:</p> + +<ul> + <li><strong>一个开始条件,</strong>它被初始化为一个特定的值 - 这是循环的起点("开始:我没有食物”,上面)。</li> + <li><strong>一个结束条件,</strong>这是循环停止的标准 - 通常计数器达到一定值。 以上所说的“我有足够的食物”吗? 假设他需要10份食物来养活他的家人。</li> + <li><strong>一个迭代器,</strong>这通常在每个连续循环上递增少量的计数器,直到达到退出条件。 我们以前没有明确说明,但是我们可以考虑一下农民能够每小时收集2份食物。 每小时后,他收集的食物量增加了两倍,他检查他是否有足够的食物。 如果他已经达到10分(退出条件),他可以停止收集回家。</li> +</ul> + +<p>在 {{glossary("伪代码")}} 中,这看起来就像下面这样:</p> + +<pre>loop(food = 0; foodNeeded = 10) { + if (food = foodNeeded) { + exit loop; + // 我们有足够的食物了,回家吧。 + } else { + food += 2; // 花一个小时多收集两个食物。 + // 循环将会继续执行。 + } +}</pre> + +<p>所以需要的食物量定为10,农民目前的数量为0。在循环的每次迭代中,我们检查农民的食物量是否等于他需要的量。 如果是这样,我们可以退出循环。 如果没有,农民花一个小时收集两部分食物,循环再次运行。</p> + +<h3 id="为何?"><font><font>为何?</font></font></h3> + +<p>在这一点上,您可能会了解循环中的高级概念,但您可能会认为“好的,但是,这有助于我编写更好的JavaScript代码?” 正如我们前面所说,循环与所做的事情都是一样的,这对于快速完成重复任务是非常有用的。</p> + +<p>通常,循环的每个连续迭代的代码将略有不同,这意味着您可以完成相同但略有不同的任务的全部负载 - 如果您有很多不同的计算要做, 做不同的一个,不一样的一个又一个!</p> + +<p>让我们来看一个例子来完美地说明为什么循环是一件好事。 假设我们想在{{htmlelement("canvas")}}元素上绘制100个随机圆(按更新按钮一次又一次地运行示例以查看不同的随机集):</p> + +<div class="hidden"> +<h6 id="Hidden_code">Hidden code</h6> + +<pre class="brush: html"><!DOCTYPE html> +<html> + <head> + <meta charset="utf-8"> + <title>Random canvas circles</title> + <style> + html { + width: 100%; + height: inherit; + background: #ddd; + } + + canvas { + display: block; + } + + body { + margin: 0; + } + + button { + position: absolute; + top: 5px; + left: 5px; + } + </style> + </head> + <body> + + <button>Update</button> + + <canvas></canvas> + + + <script> + var btn = document.querySelector('button'); + var canvas = document.querySelector('canvas'); + var ctx = canvas.getContext('2d'); + + var WIDTH = document.documentElement.clientWidth; + var HEIGHT = document.documentElement.clientHeight; + + canvas.width = WIDTH; + canvas.height = HEIGHT; + + function random(number) { + return Math.floor(Math.random()*number); + } + + function draw() { + ctx.clearRect(0,0,WIDTH,HEIGHT); + for (var i = 0; i < 100; i++) { + ctx.beginPath(); + ctx.fillStyle = 'rgba(255,0,0,0.5)'; + ctx.arc(random(WIDTH), random(HEIGHT), random(50), 0, 2 * Math.PI); + ctx.fill(); + } + } + + btn.addEventListener('click',draw); + + </script> + + </body> +</html></pre> +</div> + +<p>{{ EmbedLiveSample('Hidden_code', '100%', 400, "", "", "hide-codepen-jsfiddle") }}</p> + +<p>您现在不需要理解所有代码,但我们来看看实际绘制100个圆的那部分代码:</p> + +<pre class="brush: js">for (var i = 0; i < 100; i++) { + ctx.beginPath(); + ctx.fillStyle = 'rgba(255,0,0,0.5)'; + ctx.arc(random(WIDTH), random(HEIGHT), random(50), 0, 2 * Math.PI); + ctx.fill(); +} +</pre> + +<p> </p> + +<ul> + <li><code>random()</code>,在前面的代码中定义过了,返回一个 <code>0</code> 到 <font face="consolas, Liberation Mono, courier, monospace"><span style="background-color: rgba(220, 220, 220, 0.5);">x-1</span></font> 间的整数。</li> + <li><code>WIDTH</code> 和<code>HEIGHT</code> 浏览器内部窗口的宽度和高度。</li> +</ul> + +<p> </p> + +<p>您应该有一个基本的想法 - 我们使用一个循环来运行这个代码的100次迭代,其中每一个在页面上的随机位置绘制一个圆。 无论我们绘制100个圆,1000还是10,000,所需的代码量将是相同的。 只有一个数字必须改变。</p> + +<p>如果我们在这里没有使用循环,我们必须为我们想要绘制的每个圆重复以下代码:</p> + +<pre class="brush: js">ctx.beginPath(); +ctx.fillStyle = 'rgba(255,0,0,0.5)'; +ctx.arc(random(WIDTH), random(HEIGHT), random(50), 0, 2 * Math.PI); +ctx.fill();</pre> + +<p>这将非常无聊而且很难维持高速。 循环真的相当好用。</p> + +<h2 id="循环的标准">循环的标准</h2> + +<p>我们开始探索一些特定的循环结构。 第一个,你会经常使用到它,for循环 - 以下为for循环的语法:</p> + +<pre>for (initializer; exit-condition; final-expression) { + // code to run +}</pre> + +<p><font><font>我们有:</font></font></p> + +<ol> + <li><font><font>关键字</font></font><code>for</code><font><font>,后跟一些括号。</font></font></li> + <li><font><font>在括号内,我们有三个项目,以分号分隔:</font></font> + <ol> + <li><font><font>一个</font></font><strong>初始化器</strong><font><font> - 这通常是一个设置为一个数字的变量,它被递增来计算循环运行的次数。</font><font>它也有时被称为</font></font><strong>计数变量</strong><font><font>。</font></font></li> + <li><font><font>一个</font></font><strong>退出条件</strong><font><font> -如前面提到的,这个定义循环何时停止循环。</font><font>这通常是一个表现为比较运算符的表达式,用于查看退出条件是否已满足的测试。</font></font></li> + <li>一个<strong>最终条件</strong><font><font> -这总是被判断(或运行),每个循环已经通过一个完整的迭代消失时间。</font><font>它通常用于增加(或在某些情况下递减)计数器变量,使其更接近退出条件值。</font></font></li> + </ol> + </li> + <li><font><font>一些包含代码块的花括号 - 每次循环迭代时都会运行这个代码。</font></font></li> +</ol> + +<p><font><font>我们来看一个真实的例子,所以我们可以看出这些做得更清楚。</font></font></p> + +<pre class="brush: js">var cats = ['Bill', 'Jeff', 'Pete', 'Biggles', 'Jasmin']; +var info = 'My cats are called '; +var para = document.querySelector('p'); + +for (var i = 0; i < cats.length; i++) { + info += cats[i] + ', '; +} + +para.textContent = info;</pre> + +<p>这给我们以下输出:</p> + +<div class="hidden"> +<h6 id="Hidden_code_2">Hidden code 2</h6> + +<pre class="brush: html"><!DOCTYPE html> +<html> + <head> + <meta charset="utf-8"> + <title>Basic for loop example</title> + <style> + + </style> + </head> + <body> + + <p></p> + + + <script> + var cats = ['Bill', 'Jeff', 'Pete', 'Biggles', 'Jasmin']; + var info = 'My cats are called '; + var para = document.querySelector('p'); + + for (var i = 0; i < cats.length; i++) { + info += cats[i] + ', '; + } + + para.textContent = info; + + </script> + + </body> +</html></pre> +</div> + +<p>{{ EmbedLiveSample('Hidden_code_2', '100%', 60, "", "", "hide-codepen-jsfiddle") }}</p> + +<div class="note"> +<p><strong>注</strong>: 您可以<a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/loops/basic-for.html">在GitHub上找到这段示例代码</a>。 (也可以<a href="http://mdn.github.io/learning-area/javascript/building-blocks/loops/basic-for.html">在线运行</a>)。</p> +</div> + +<p>这显示了一个循环用于迭代数组中的项目,并与每个项目进行一些操作 - JavaScript中非常常见的模式。 这里:</p> + +<ol> + <li>迭代器<code>i</code>从0开始(<code>var i = 0</code>)。</li> + <li>循环将会一直运行直到它不再小于猫数组的长度。 这很重要 - 退出条件显示循环仍然运行的条件。 所以在这种情况下,<code><cats.length</code>仍然是真的,循环仍然运行。</li> + <li>在循环中,我们将当前的循环项(<code>cats[i]</code>是<code>cats[当前下标的任何东西]</code>)以及逗号和空格连接到<code>info</code>变量的末尾。 所以: + <ol> + <li>在第一次运行中,<code>i = 0</code>,所以<code>cats[0] +','将</code>被连接到<code>info("Bill")</code>上。</li> + <li>在第二次运行中,<code>i = 1</code>,所以<code>cats[1] +','</code>将被连接到<code>info("Jeff")</code>上。</li> + <li>等等。 每次循环运行后,1将被添加到i(i ++),然后进程将再次启动。</li> + </ol> + </li> + <li>当等于<code>cats.length</code>时,循环将停止,浏览器将移动到循环下面的下一个代码位。</li> +</ol> + +<div class="note"> +<p><strong>注</strong>: 我们将退出条件设为<code>< cats.length</code>,而不是<code><= cats.length</code>是因为计算机从0开始,而不是1 - 开始时<code>i</code>是0,并且逐步增加到i<code> = 4</code>(最后一个数组的索引)。 <code>cats.length</code>返回5,因为数组中有5个项目,但是我们不希望达到<code>i = 5</code>,因为这将返回未定义的最后一个项目(没有索引为5的数组项目)。 所以我们想要比<code>cats.length</code>(<code>i <</code>)少1,而不是<code>cats.length</code>(<code>i <=</code>)。</p> +</div> + +<div class="note"> +<p><strong>注</strong>: 退出条件的一个常见错误是使它们使用“等于”(<code>===</code>)而不是说“小于或等于”(<code><=</code>)。 如果我们想要运行我的循环到<code>i = 5</code>,退出条件将需要是<code>i <= cats.length</code>。如果我们设置为<code>i === cats.length</code>,循环将不会运行,因为在第一次循环迭代时 i 不等于5,所以循环会立即停止。</p> +</div> + +<p>我们留下的一个小问题是最后的输出句子形式不是很好:</p> + +<blockquote> +<p>My cats are called Bill, Jeff, Pete, Biggles, Jasmin,</p> +</blockquote> + +<p>理想情况下,我们想改变最后循环迭代中的连接,以便在句子末尾没有逗号。 嗯,没问题 - 我们可以很高兴地在我们的for循环中插入一个条件来处理这种特殊情况:</p> + +<pre class="brush: js">for (var i = 0; i < cats.length; i++) { + if (i === cats.length - 1) { + info += 'and ' + cats[i] + '.'; + } else { + info += cats[i] + ', '; + } +}</pre> + +<div class="note"> +<p><strong>注</strong>: 您可以<a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/loops/basic-for-improved.html">在GitHub上找到这个例子</a>。(也可以<a href="http://mdn.github.io/learning-area/javascript/building-blocks/loops/basic-for-improved.html">在线运行</a>)</p> +</div> + +<div class="warning"> +<p><strong>重要:</strong> 使用<code>for</code>- 与所有循环一样,您必须确保初始化程序被迭代,以便最终达到退出条件。 如果没有,循环将永不停止,浏览器将强制它停止,否则会崩溃。 这被称为无限循环。</p> +</div> + +<h2 id="使用break退出循环">使用break退出循环</h2> + +<p>如果要在所有迭代完成之前退出循环,可以使用break语句。 当我们查看switch语句时,我们已经在上一篇文章中遇到过这样的情况 - 当switch语句中符合输入表达式的情况满足时,break语句立即退出switch语句并移动到代码之后。</p> + +<p>与循环相同 - break语句将立即退出循环,并使浏览器移动到跟随它的任何代码。</p> + +<p>说我们想搜索一系列联系人和电话号码,只返回我们想要找的号码? 首先,一些简单的HTML - 一个文本{{htmlelement("input")}},允许我们输入一个名称来搜索,一个{{htmlelement("button")}}元素来提交搜索,以及一个{{htmlelement ("p")}}元素显示结果:<br> + </p> + +<pre class="brush: html"><label for="search">Search by contact name: </label> +<input id="search" type="text"> +<button>Search</button> + +<p></p></pre> + +<p>然后是JavaScript:</p> + +<pre class="brush: js">var contacts = ['Chris:2232322', 'Sarah:3453456', 'Bill:7654322', 'Mary:9998769', 'Dianne:9384975']; +var para = document.querySelector('p'); +var input = document.querySelector('input'); +var btn = document.querySelector('button'); + +btn.addEventListener('click', function(){ + var searchName = input.value; + input.value = ''; + input.focus(); + for (var i = 0; i < contacts.length; i++) { + var splitContact = contacts[i].split(':'); + if (splitContact[0] === searchName) { + para.textContent = splitContact[0] + '\'s number is ' + splitContact[1] + '.'; + break; + } else { + para.textContent = 'Contact not found.'; + } + } +});</pre> + +<div class="hidden"> +<h6 id="Hidden_code_3">Hidden code 3</h6> + +<pre class="brush: html"><!DOCTYPE html> +<html> + <head> + <meta charset="utf-8"> + <title>Simple contact search example</title> + <style> + + </style> + </head> + <body> + + <label for="search">Search by contact name: </label> + <input id="search" type="text"> + <button>Search</button> + + <p></p> + + + <script> + var contacts = ['Chris:2232322', 'Sarah:3453456', 'Bill:7654322', 'Mary:9998769', 'Dianne:9384975']; + var para = document.querySelector('p'); + var input = document.querySelector('input'); + var btn = document.querySelector('button'); + + btn.addEventListener('click', function() { + var searchName = input.value; + input.value = ''; + input.focus(); + for (var i = 0; i < contacts.length; i++) { + var splitContact = contacts[i].split(':'); + if (splitContact[0] === searchName) { + para.textContent = splitContact[0] + '\'s number is ' + splitContact[1] + '.'; + break; + } else if (i === contacts.length-1) + para.textContent = 'Contact not found.'; + } + } + }); + </script> + + </body> +</html></pre> +</div> + +<p>{{ EmbedLiveSample('Hidden_code_3', '100%', 100, "", "", "hide-codepen-jsfiddle") }}</p> + +<ol> + <li>首先我们有一些变量定义 - 我们有一个联系信息数组,每个项目是一个字符串,包含一个以冒号分隔的名称和电话号码。</li> + <li>接下来,我们将一个事件监听器附加到按钮(<code>btn</code>)上,这样当按下它时,运行一些代码来执行搜索并返回结果。</li> + <li>我们将输入的值输入到一个名为<code>searchName</code>的变量中,然后清空文本输入并重新对准它,准备进行下一个搜索。</li> + <li>现在有趣的部分,for循环: + <ol> + <li>我们的计数器开始时为在0,直到计数器不再小于<code>contacts.length</code>,并在循环的每次迭代之后将<code>i</code>递增1。</li> + <li>在循环中,我们首先将当前联系人(<code>contacts [i]</code>)拆分为冒号字符,并将生成的两个值存储在名为<code>splitContact</code>的数组中。</li> + <li>然后,我们使用条件语句来测试<code>splitContact [0]</code>(联系人姓名)是否等于输入的<code>searchName</code>。 如果是,我们在段落中输入一个字符串来报告联系人的号码,并使用break来结束循环。</li> + </ol> + </li> + <li>在<code>(contacts.length-1)</code> 迭代后,如果联系人姓名与输入的搜索不符,则段落文本设置为“未找到联系人”,循环继续迭代。</li> +</ol> + +<div class="note"> +<p><strong>注:</strong>您可以<a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/loops/contact-search.html">在GitHub上找到这个例子</a>或<a href="http://mdn.github.io/learning-area/javascript/building-blocks/loops/contact-search.html">在线运行</a>。</p> +</div> + +<h2 id="使用continue跳过迭代">使用continue跳过迭代</h2> + +<p>continue语句以类似的方式工作,而不是完全跳出循环,而是跳过当前循环而执行下一个循环。 我们来看另外一个例子,它把一个数字作为一个输入,并且只返回开平方之后为整数的数字(整数)。</p> + +<p>HTML与最后一个例子基本相同 - 一个简单的文本输入和一个输出段落。 JavaScript也是一样的,虽然循环本身有点不同:</p> + +<pre class="brush: js">var num = input.value; + +for (var i = 1; i <= num; i++) { + var sqRoot = Math.sqrt(i); + if (Math.floor(sqRoot) !== sqRoot) { + continue; + } + + para.textContent += i + ' '; +}</pre> + +<p>Here's the output:</p> + +<div class="hidden"> +<h6 id="Hidden_code_4">Hidden code 4</h6> + +<pre class="brush: html"><!DOCTYPE html> +<html> + <head> + <meta charset="utf-8"> + <title>Integer squares generator</title> + <style> + + </style> + </head> + <body> + + <label for="number">Enter number: </label> + <input id="number" type="text"> + <button>Generate integer squares</button> + + <p>Output: </p> + + + <script> + var para = document.querySelector('p'); + var input = document.querySelector('input'); + var btn = document.querySelector('button'); + + btn.addEventListener('click', function() { + para.textContent = 'Output: '; + var num = input.value; + input.value = ''; + input.focus(); + for (var i = 1; i <= num; i++) { + var sqRoot = Math.sqrt(i); + if (Math.floor(sqRoot) !== sqRoot) { + continue; + } + + para.textContent += i + ' '; + } + }); + </script> + + </body> +</html></pre> +</div> + +<p>{{ EmbedLiveSample('Hidden_code_4', '100%', 100, "", "", "hide-codepen-jsfiddle") }}</p> + +<ol> + <li>在这种情况下,输入应为数字(<code>num</code>)。 for循环给定一个从1开始的计数器(在这种情况下,我们对0不感兴趣),一个退出条件,当计数器大于输入<code>num</code>时循环将停止,并且迭代器的计数器将每次增加1。</li> + <li>在循环中,我们使用<code>Math.sqrt(i)</code>找到每个数字的平方根,然后测试平方根是否是一个整数,通过判断当它被向下取整时,它是否与自身相同(这是<code>Math.floor(...)</code>对传递的数字的作用)。</li> + <li>如果平方根和四舍五入的平方根不相等(<code>!==</code>),则表示平方根不是整数,因此我们对此不感兴趣。 在这种情况下,我们使用continue语句跳过当前循环而执行下一个循环迭代,而不在任何地方记录该数字。</li> + <li>如果平方根是一个整数,我们完全跳过if块,所以continue语句不被执行; 相反,我们将当前i值加上一个空格连接到段落内容的末尾。</li> +</ol> + +<div class="note"> +<p><strong>注:</strong>您可以<a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/loops/integer-squares.html">在GitHub上查看完整代码</a>,或者<a href="http://mdn.github.io/learning-area/javascript/building-blocks/loops/integer-squares.html">在线运行</a>。</p> +</div> + +<h2 id="while语句和do_..._while语句">while语句和do ... while语句</h2> + +<p><code>for</code> 不是JavaScript中唯一可用的循环类型。 实际上还有很多其他的,而现在你不需要理解所有这些,所以值得看几个人的结构,这样你就可以在稍微不同的方式识别出相同的功能。</p> + +<p>首先,我们来看看while循环。 这个循环的语法如下所示:</p> + +<pre>initializer +while (exit-condition) { + // code to run + + final-expression +}</pre> + +<p>除了在循环之前设置初始化器变量,并且在运行代码之后,循环中包含final-expression,而不是这两个项目被包含在括号中,这与以前的for循环非常类似。 退出条件包含在括号内,前面是while关键字而不是for。</p> + +<p>同样的三个项目仍然存在,它们仍然以与for循环中相同的顺序定义 - 这是有道理的,因为您必须先定义一个初始化器,然后才能检查它是否已到达退出条件; 在循环中的代码运行(迭代已经完成)之后,运行最后的条件,这只有在尚未达到退出条件时才会发生。</p> + +<p>我们再来看看我们的猫列表示例,但是重写了一个while循环:</p> + +<pre class="brush: js">var i = 0; + +while (i < cats.length) { + if (i === cats.length - 1) { + info += 'and ' + cats[i] + '.'; + } else { + info += cats[i] + ', '; + } + + i++; +}</pre> + +<div class="note"> +<p><strong>Note</strong>: This still works just the same as expected — have a look at it <a href="http://mdn.github.io/learning-area/javascript/building-blocks/loops/while.html">running live on GitHub</a> (also view the <a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/loops/while.html">full source code</a>).</p> +</div> + +<p><a href="/en-US/docs/Web/JavaScript/Reference/Statements/do...while">do...while</a>循环非常类似但在while后提供了终止条件:</p> + +<pre>initializer +do { + // code to run + + final-expression +} while (exit-condition)</pre> + +<p>在这种情况下,在循环开始之前,初始化程序先重新开始。 do关键字直接在包含要运行的代码的花括号和终止条件之前。</p> + +<p>这里的区别在于退出条件是一切都包含在括号中,而后面是一个while关键字。 在do ... while循环中,花括号中的代码总是在检查之前运行一次,以查看是否应该再次执行(在while和for中,检查首先出现,因此代码可能永远不会执行)。</p> + +<p>我们再次重写我们的猫列表示例,以使用do...while循环:</p> + +<pre class="brush: js">var i = 0; + +do { + if (i === cats.length - 1) { + info += 'and ' + cats[i] + '.'; + } else { + info += cats[i] + ', '; + } + + i++; +} while (i < cats.length);</pre> + +<div class="note"> +<p><strong>Note</strong>: 再一次,它正如我们期望的那样工作 — 看一看它在<a href="http://mdn.github.io/learning-area/javascript/building-blocks/loops/do-while.html">Github在线运行</a> (或者查看<a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/loops/do-while.html">完整源代码</a>).</p> +</div> + +<div class="warning"> +<p><strong>Important</strong>: 使用 while 和 do...while — 所有循环都一样 — 你必须保证初始变量是迭代的,那么它才会逐渐地达到退出条件. 不然, 它将会永远循环下去, 要么浏览器会强制终止它,要么它自己会崩溃. 这称为无限循环.</p> +</div> + +<h2 id="主动学习:启动倒计时!">主动学习:启动倒计时!</h2> + +<p>在这个练习中,我们希望你打印出一个简单的启动倒计时到输出框,从10到关闭。 具体来说,我们希望你:</p> + +<ul> + <li>从10下降到0.我们为您提供了一个初始化器 - var i = 10;</li> + <li>对于每次迭代,创建一个新的段落并将其附加到输出<div>,我们使用<code>var output = document.querySelector('.output');</code>。在评论中,我们为您提供了需要在循环中某处使用的三条代码行: + <ul> + <li><code>var para = document.createElement('p');</code> —新建一个段落。</li> + <li><code>output.appendChild(para);</code> — 将段落附加到输出 <code><div></code>中。</li> + <li><code>para.textContent =</code> — 段落内的文字等于您放在右侧的任何内容。</li> + </ul> + </li> + <li>不同的迭代数字需要将不同的文本放在该迭代的段落中(您需要一个条件语句和多个<code>para.textContent = lines</code>): + <ul> + <li>如果数字是10,打印“Countdown 10”到段落。</li> + <li>如果数字为0,请打印“Blast off!” 到段落。</li> + <li>对于任何其他数字,只打印段落的数字。</li> + </ul> + </li> + <li>记住要包括一个迭代器! 然而,在这个例子中,我们在每次迭代之后都下降,而不是上升,所以你不想要<code>i++</code> - 你如何向下迭代?</li> +</ul> + +<p>如果您犯了错误,您可以随时使用“重置”按钮重置该示例。 如果你真的卡住了,请按“显示解决方案”来查看解决方案。</p> + +<div class="hidden"> +<h6 id="Active_learning">Active learning</h6> + +<pre class="brush: html"><div class="output" style="height: 410px;overflow: auto;"> + +</div> + + +<textarea id="code" class="playable-code" style="height: 300px;"> +var output = document.querySelector('.output'); +output.innerHTML = ''; + +// var i = 10; + +// var para = document.createElement('p'); +// para.textContent = ; +// output.appendChild(para); +</textarea> + +<div class="playable-buttons"> + <input id="reset" type="button" value="Reset"> + <input id="solution" type="button" value="Show solution"> +</div> +</pre> + +<pre class="brush: js">var textarea = document.getElementById('code'); +var reset = document.getElementById('reset'); +var solution = document.getElementById('solution'); +var code = textarea.value; + +function updateCode() { + eval(textarea.value); +} + +reset.addEventListener('click', function() { + textarea.value = code; + updateCode(); +}); + +solution.addEventListener('click', function() { + textarea.value = jsSolution; + updateCode(); +}); + +var jsSolution = 'var output = document.querySelector(\'.output\');\noutput.innerHTML = \'\';\n\nvar i = 10;\n\nwhile(i >= 0) {\n var para = document.createElement(\'p\');\n if(i === 10) {\n para.textContent = \'Countdown \' + i;\n } else if(i === 0) {\n para.textContent = \'Blast off!\';\n } else {\n para.textContent = i;\n }\n\n output.appendChild(para);\n\n i--;\n}'; + +textarea.addEventListener('input', updateCode); +window.addEventListener('load', updateCode); +</pre> +</div> + +<p>{{ EmbedLiveSample('Active_learning', '100%', 880, "", "", "hide-codepen-jsfiddle") }}</p> + +<h2 id="主动学习:填写来宾列表">主动学习:填写来宾列表</h2> + +<p>在本练习中,我们希望您获取存储在数组中的名称列表,并将其放入来宾列表中。 但这不是那么容易 - 我们不想让菲尔和洛拉进来,因为他们是贪婪和粗鲁的,总是吃所有的食物! 我们有两个名单,一个是客人承认的,一个是客人拒绝的。</p> + +<p>具体来说,我们希望你:</p> + +<ul> + <li>编写一个循环,它将从0迭代到people数组的长度。 你需要从一个初始化器<code>var i = 0</code>开始,但是你需要什么退出条件?</li> + <li>在每个循环迭代期间,使用条件语句检查当前数组项是否等于“Phil”或“Lola”: + <ul> + <li>如果是,则将数组项连接到拒绝段落的<code>textContent</code>的末尾,后跟逗号和空格。</li> + <li>如果不是,则将数组项连接到接收段落的<code>textContent</code>的末尾,后跟逗号和空格。</li> + </ul> + </li> +</ul> + +<p>我们已经提供给您:</p> + +<ul> + <li><code>var i = 0;</code> — 你的初始化程序</li> + <li><code>refused.textContent +=</code> - 将连接某些东西的行的开头,结束于<code>refused.textContent</code>。</li> + <li><code>admitted.textContent +=</code> - 将连接某些内容到一行的结尾的行的开始。</li> +</ul> + +<p>额外的奖金问题 - 成功完成上述任务后,您将留下两个名称列表,用逗号分隔,但它们将不整齐 - 每个结尾处都会有一个逗号。 你可以制定出如何在每种情况下编写最后一个逗号的行,并添加一个完整的停止? 看看有用的字符串方法文章的帮助。</p> + +<p>如果您犯了错误,您可以随时使用“重置”按钮重置该示例。 如果你真的卡住了,请按“显示解决方案”来查看解决方案。</p> + +<div class="hidden"> +<h6 id="Active_learning_2">Active learning 2</h6> + +<pre class="brush: html"><div class="output" style="height: 100px;overflow: auto;"> + <p class="admitted">Admit: </p> + <p class="refused">Refuse: </p> +</div> + +<textarea id="code" class="playable-code" style="height: 400px;"> +var people = ['Chris', 'Anne', 'Colin', 'Terri', 'Phil', 'Lola', 'Sam', 'Kay', 'Bruce']; + +var admitted = document.querySelector('.admitted'); +var refused = document.querySelector('.refused'); +admitted.textContent = 'Admit: '; +refused.textContent = 'Refuse: ' + +// var i = 0; + +// refused.textContent += ; +// admitted.textContent += ; + +</textarea> + +<div class="playable-buttons"> + <input id="reset" type="button" value="Reset"> + <input id="solution" type="button" value="Show solution"> +</div> +</pre> + +<pre class="brush: js">var textarea = document.getElementById('code'); +var reset = document.getElementById('reset'); +var solution = document.getElementById('solution'); +var code = textarea.value; + +function updateCode() { + eval(textarea.value); +} + +reset.addEventListener('click', function() { + textarea.value = code; + updateCode(); +}); + +solution.addEventListener('click', function() { + textarea.value = jsSolution; + updateCode(); +}); + +var jsSolution = 'var people = [\'Chris\', \'Anne\', \'Colin\', \'Terri\', \'Phil\', \'Lola\', \'Sam\', \'Kay\', \'Bruce\'];\n\nvar admitted = document.querySelector(\'.admitted\');\nvar refused = document.querySelector(\'.refused\');\n\nvar i = 0;\n\ndo {\n if(people[i] === \'Phil\' || people[i] === \'Lola\') {\n refused.textContent += people[i] + \', \';\n } else {\n admitted.textContent += people[i] + \', \';\n }\n i++;\n} while(i < people.length);\n\nrefused.textContent = refused.textContent.slice(0,refused.textContent.length-2) + \'.\';\nadmitted.textContent = admitted.textContent.slice(0,admitted.textContent.length-2) + \'.\';'; + +textarea.addEventListener('input', updateCode); +window.addEventListener('load', updateCode); +</pre> +</div> + +<p>{{ EmbedLiveSample('Active_learning_2', '100%', 680, "", "", "hide-codepen-jsfiddle") }}</p> + +<h2 id="应该使用哪种循环类型?">应该使用哪种循环类型?</h2> + +<p>对于基本用途,for,while和do ... while循环大部分可互换。 他们都可以用来解决相同的问题,你使用哪一个将在很大程度上取决于你的个人偏好 - 哪一个你最容易记住或最直观的。 我们再来看看他们。</p> + +<p>首先是 <code>for</code>:</p> + +<pre>for (initializer; exit-condition; final-expression) { + // code to run +}</pre> + +<p><code>while</code>:</p> + +<pre>initializer +while (exit-condition) { + // code to run + + final-expression +}</pre> + +<p>最后是 <code>do...while</code>:</p> + +<pre>initializer +do { + // code to run + + final-expression +} while (exit-condition)</pre> + +<p>我们建议使用<code>for</code>,因为它可能是最简单地帮你记住一切 - 初始化程序,退出条件和最终表达式都必须整齐地放入括号,所以很容易看到他们在哪里并检查你没有丢失他们。</p> + +<div class="note"> +<p><strong>注:</strong>还有其他循环类型/特性,这些特性在 高级/专门 的情况下是有用的,超出了本文的范围。如果您想进一步了解循环学习,请阅读我们的高级<a href="/en-US/docs/Web/JavaScript/Guide/Loops_and_iteration">循环和迭代指南</a>。</p> +</div> + +<h2 id="结论">结论</h2> + +<p>本文向您展示了背后的基本概念,以及JavaScript中循环代码时可用的不同选项。 你现在应该明白为什么循环是一个处理重复代码的好机制,并且在你自己的例子中使用它们!</p> + +<p>如果您有什么不明白的地方,可以再通读一遍,或者<a href="/en-US/Learn#Contact_us">联系我们</a>寻求帮助。</p> + +<h2 id="相关链接">相关链接</h2> + +<ul> + <li><a href="/en-US/docs/Web/JavaScript/Guide/Loops_and_iteration">Loops and iteration in detail</a></li> + <li><a href="/en-US/docs/Web/JavaScript/Reference/Statements/for">for statement reference</a></li> + <li><a href="/en-US/docs/Web/JavaScript/Reference/Statements/while">while</a> and <a href="/en-US/docs/Web/JavaScript/Reference/Statements/do...while">do...while</a> references</li> + <li><a href="/en-US/docs/Web/JavaScript/Reference/Statements/break">break</a> and <a href="/en-US/docs/Web/JavaScript/Reference/Statements/continue">continue</a> references</li> + <li> + <p class="entry-title"><a href="https://www.impressivewebs.com/javascript-for-loop/">What’s the Best Way to Write a JavaScript For Loop?</a> — some advanced loop best practices</p> + </li> +</ul> + +<p>{{PreviousMenuNext("Learn/JavaScript/Building_blocks/conditionals","Learn/JavaScript/Building_blocks/Functions", "Learn/JavaScript/Building_blocks")}}</p> + +<p> </p> + +<h2 id="在本单元中">在本单元中</h2> + +<ul> + <li><a href="https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Building_blocks/conditionals">Making decisions in your code — conditionals</a></li> + <li><a href="https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Building_blocks/Looping_code">Looping code</a></li> + <li><a href="https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Building_blocks/Functions">Functions — reusable blocks of code</a></li> + <li><a href="https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Building_blocks/Build_your_own_function">Build your own function</a></li> + <li><a href="https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Building_blocks/Return_values">Function return values</a></li> + <li><a href="https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Building_blocks/Events">Introduction to events</a></li> + <li><a href="https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Building_blocks/Image_gallery">Image gallery</a></li> +</ul> + +<p> </p> diff --git a/files/zh-cn/learn/javascript/building_blocks/return_values/index.html b/files/zh-cn/learn/javascript/building_blocks/return_values/index.html new file mode 100644 index 0000000000..38f9fe0eff --- /dev/null +++ b/files/zh-cn/learn/javascript/building_blocks/return_values/index.html @@ -0,0 +1,172 @@ +--- +title: 函数返回值 +slug: learn/JavaScript/Building_blocks/Return_values +tags: + - JavaScript + - 函数 + - 返回值 +translation_of: Learn/JavaScript/Building_blocks/Return_values +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/JavaScript/Building_blocks/Build_your_own_function","Learn/JavaScript/Building_blocks/Events", "Learn/JavaScript/Building_blocks")}}</div> + +<p class="summary">函数返回值-是本章中最后一个基础概念,让我们一起来瞧瞧.。有些函数在执行完毕后不会返回一个有用的值,但有些会, 重要的是理解返回的是什么,怎样使用这些值在你的代码中,我们将在下面讨论这些。</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">前提:</th> + <td> + <p>基础的计算机知识, 懂得基础的HTML 和CSS, <a href="/en-US/docs/Learn/JavaScript/First_steps">JavaScript </a>第一步学习, 函数-<a href="/en-US/docs/Learn/JavaScript/Building_blocks/Functions"> </a>可重用的代码块.</p> + </td> + </tr> + <tr> + <th scope="row">目标:</th> + <td>理解什么函数的返回值 , 和如何使用它们</td> + </tr> + </tbody> +</table> + +<h2 id="什么是返回值">什么是返回值?</h2> + +<p>返回值意如其名,是指函数执行完毕后返回的值。你已经多次遇见过返回值,尽管你可能没有明确的考虑过他们。让我们一起回看一些熟悉的代码:</p> + +<pre class="brush: js notranslate">var myText = 'I am a string'; +var newString = myText.replace('string', 'sausage'); +console.log(newString); +// the replace() string function takes a string, +// replaces one substring with another, and returns +// a new string with the replacement made</pre> + +<p>在第一篇函数文章中,我们确切地看到了这一块代码。我们对 <code>myText</code> 字符串调用 <a href="https://wiki.developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/replace">replace()</a> 功能,并通过这两个参数的字符串查找,和子串替换它。当这个函数完成(完成运行)后,它返回一个值,这个值是一个新的字符串,它具有替换的功能。在上面的代码中,我们保存这个返回值,以作为<code>newString</code>变量的内容。</p> + +<p>如果你看看替换功能MDN参考页面,你会看到一个<a href="/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/String/replace#Return_value">返回值</a>。知道和理解函数返回的值是非常有用的,因此我们尽可能地包含这些信息。</p> + +<p>一些函数没有返回值就像(在我们的参考页中,返回值在这种情况下被列出为空值 <code>void</code> 或未定义值 <code>undefined</code> 。).例如, 我们在前面文章中创建的 <a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/functions/function-stage-4.html#L50">displayMessage() function</a> , 由于调用的函数的结果,没有返回特定的值。它只是让一个提示框出现在屏幕的某个地方——就是这样!</p> + +<p>通常,返回值是用在函数在计算某种中间步骤。你想得到最终结果,其中包含一些值。那些值需要通过一个函数计算得到,然后返回结果可用于计算的下一个阶段。</p> + +<h3 id="在自定义的函数中使用返回值">在自定义的函数中使用返回值</h3> + +<p>要从自定义函数返回值,您需要使用…等待它… <a href="https://wiki.developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/return">return</a> 关键字。 我们最近在<a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/loops/random-canvas-circles.html">random-canvas-circles.html</a>示例中看到了这一点。 我们的 <code>draw()</code> 函数绘制100随机圆在HTML的{{htmlelement("canvas")}}:</p> + +<pre class="brush: js notranslate">function draw() { + ctx.clearRect(0,0,WIDTH,HEIGHT); + for (var i = 0; i < 100; i++) { + ctx.beginPath(); + ctx.fillStyle = 'rgba(255,0,0,0.5)'; + ctx.arc(random(WIDTH), random(HEIGHT), random(50), 0, 2 * Math.PI); + ctx.fill(); + } +}</pre> + +<p>在每个循环迭代,<code>random()</code>函数调用了三次,分别生成当前圆的x坐标,一个随机值Y坐标和半径。<code>random()</code>函数接受一个参数-一个整数,返回0到这个整数之间的随机数。看起来像这样:</p> + +<pre class="brush: js notranslate">function randomNumber(number) { + return Math.floor(Math.random()*number); +}</pre> + +<p>这也可以写成下面这样:</p> + +<pre class="brush: js notranslate">function randomNumber(number) { + var result = Math.floor(Math.random()*number); + return result; +}</pre> + +<p>但是第一个版本写得更快,而且更紧凑。</p> + +<p>我们每次调用函数都返回<code>Math.floor(Math.random()*number)</code>计算的数学结果。这个返回值出现在调用函数的位置上,并且代码继续。例如,如果我们运行下面的行:</p> + +<pre class="brush: js notranslate">ctx.arc(random(WIDTH), random(HEIGHT), random(50), 0, 2 * Math.PI);</pre> + +<p>这三次<code>random()</code>调用分别返回值500, 200和35,实际上这一行这样运行:</p> + +<pre class="brush: js notranslate">ctx.arc(500, 200, 35, 0, 2 * Math.PI);</pre> + +<p>在运行该行之前,首先运行该行上的函数调用,并用其返回值替换该函数调用。</p> + +<h2 id="主动学习:我们自己的返回值函数">主动学习:我们自己的返回值函数</h2> + +<p>让我们着手编写具有我们自己的返回值的函数。</p> + +<ol> + <li>首先,从GitHub的<a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/functions/function-library.html">function-library.html</a>文件复制一份本地副本。这是一个简单的HTML页面包含一个 {{htmlelement("input")}} 文本域和一个段落。 还有一个 {{htmlelement("script")}} 元素,我们在两个变量中存储了对两个HTML元素的引用。这个小页面允许你在文本框中输入一个数字,并在下面的段落中显示不同的数字。</li> + <li>让我们添加一些有用的函数。在现有的两行JavaScript下面,添加以下函数定义: + <pre class="brush: js notranslate">function squared(num) { + return num * num; +} + +function cubed(num) { + return num * num * num; +} + +function factorial(num) { + var x = num; + while (x > 1) { + num *= x-1; + x--; + } + return num; +}</pre> + <code>squared()</code> 和 <code>cubed()</code> 功能是相当明显的-他们的平方或立方的数作为一个参数返回。factorial()函数返回给定数字的阶乘。</li> + <li>接下来,我们将包括一种打印输入到文本输入中的数字的信息的方法。在现有函数下面输入以下事件处理程序: + <pre class="brush: js notranslate">input.onchange = function() { + var num = input.value; + if (isNaN(num)) { + para.textContent = 'You need to enter a number!'; + } else { + para.textContent = num + ' squared is ' + squared(num) + '. ' + + num + ' cubed is ' + cubed(num) + '. ' + + num + ' factorial is ' + factorial(num) + '.'; + } +}</pre> + + <p>这里我们创建一个<code>onchange</code>事件处理程序,当文本框上面的change事件被触发的之后,事件处理程序就会运行 - 就是说,一个新的值被输入到文本框并且被提交(就比如,输入一个值,然后按Tab)。当这个匿名函数运行时,输入框中的值将被存储在<code>num</code>变量中。</p> + + <p>接下来,我们进行条件测试——如果输入的值不是数字,则在段落中打印错误消息。if语句判断<a href="/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/isNaN">isNaN(num)</a>表达式是否返回true。我们用<code>isNaN()</code>函数测试<code>num</code>的值是否不是一个数字-如果不是数字,就返回<code>true</code>,否则返回<code>false</code>。</p> + + <p>如果测试返回false,则数值是一个数字,所以我们在段落元素中打印出一个句子,说明数字的平方、立方体和阶乘是什么。这句话叫squared(),cubed(),和factorial()函数来获得所需的值。</p> + </li> + <li>保存您的代码,将其加载到浏览器中,然后尝试. </li> +</ol> + +<div class="note"> +<p><strong>Note</strong>:如果你有麻烦让例子工作,对比<a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/functions/function-library-finished.html">GitHub的已完成版</a>检查你的代码(或<a href="http://mdn.github.io/learning-area/javascript/building-blocks/functions/function-library-finished.html">看它在线运行</a>),或寻求我们的帮助。</p> +</div> + +<p>在这一点上,我们希望您编写一个自己的几个函数,并将它们添加到库中。这个数的平方根或立方根,或一个圆的周长和半径是多少?</p> + +<p>这个练习提出了一些重要的观点,除了研究如何使用返回语句之外。此外,我们还有:</p> + +<ul> + <li>查看另一个将错误处理写入函数的示例。它是否提供了任何必要的参数通常是一个好主意,另一方面对可选参数提供默认值。这样,你的程序就不太可能出错了。</li> + <li>关于创建函数库思想的思考。随着你深入到你的编程生涯,你将开始一次又一次地做同样的事情。这是一个好主意,开始保持你自己的实用工具库,你经常使用-你可以把它们复制到你的新代码,甚至只是把它应用到任何你需要的HTML页面。</li> +</ul> + +<h2 id="结论">结论</h2> + +<p>因此,我们让它-功能是有趣的,非常有用的,虽然有很多要谈论他们的语法和功能,相当容易理解的正确的文章学习。</p> + +<p>如果您有什么不明白的地方,可以再通读一遍,或者<a href="https://developer.mozilla.org/en-US/Learn#Contact_us">联系我们</a>寻求帮助。</p> + +<h2 id="参见">参见</h2> + +<ul> + <li><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions">Functions in-depth</a> — 详细介绍更多高级功能相关信息的指南。</li> + <li><a href="https://www.impressivewebs.com/callback-functions-javascript/">Callback functions in JavaScript</a> — 一个常见的JavaScript模式是把一个函数传递给另一个函数作为参数,然后在第一个函数中调用它。这有点超出了这门课的范围,但值得学习很久。</li> +</ul> + +<p>{{PreviousMenuNext("Learn/JavaScript/Building_blocks/Build_your_own_function","Learn/JavaScript/Building_blocks/Events", "Learn/JavaScript/Building_blocks")}}</p> + +<h2 id="在本单元中">在本单元中</h2> + +<ul> + <li><a href="https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Building_blocks/conditionals">Making decisions in your code — conditionals</a></li> + <li><a href="https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Building_blocks/Looping_code">Looping code</a></li> + <li><a href="https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Building_blocks/Functions">Functions — reusable blocks of code</a></li> + <li><a href="https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Building_blocks/Build_your_own_function">Build your own function</a></li> + <li><a href="https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Building_blocks/Return_values">Function return values</a></li> + <li><a href="https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Building_blocks/Events">Introduction to events</a></li> + <li><a href="https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Building_blocks/Image_gallery">Image gallery</a></li> +</ul> diff --git a/files/zh-cn/learn/javascript/building_blocks/相片走廊/index.html b/files/zh-cn/learn/javascript/building_blocks/相片走廊/index.html new file mode 100644 index 0000000000..22101b20ba --- /dev/null +++ b/files/zh-cn/learn/javascript/building_blocks/相片走廊/index.html @@ -0,0 +1,244 @@ +--- +title: 照片库 +slug: learn/JavaScript/Building_blocks/相片走廊 +tags: + - 事件 + - 事件句柄 + - 初学者 + - 学习 + - 循环 + - 评估 +translation_of: Learn/JavaScript/Building_blocks/Image_gallery +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenu("Learn/JavaScript/Building_blocks/Events", "Learn/JavaScript/Building_blocks")}}</div> + +<p class="summary">我们已经学习了 JavaScript 基础的块结构,下面我们通过编写一个常见的基于 JavaScript 的照片库来测验一下你对于循环、函数、条件和事件的掌握情况。</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">预备知识:</th> + <td>请读完本章其它所有小节的内容后再开始这个测验。</td> + </tr> + <tr> + <th scope="row">目标:</th> + <td>测试你对 JavaScript 的循环、函数、条件语句和事件处理的掌握程度。</td> + </tr> + </tbody> +</table> + +<h2 id="起点">起点</h2> + +<p><a href="https://raw.githubusercontent.com/roy-tian/learning-area/master/javascript/building-blocks/gallery/gallery-start.zip">下载压缩包</a> 并在本地解压。</p> + +<div class="note"> +<p><strong>注</strong>:你还可以使用类似 <a class="external external-icon" href="http://jsbin.com/">JSBin</a> 或 <a class="external external-icon" href="https://thimble.mozilla.org/">Thimble</a> 这些在线编辑器来完成测验。你可以把 HTML、CSS 和 JavaScript 代码复制过去。如果你选的工具没有独立的 JavaScript/CSS 板面,可以随时在 HTML 页面中添加 <code><script></code>/<code><style></code> 元素。</p> +</div> + +<h2 id="项目简介">项目简介</h2> + +<p>我们提供了一些 HTML、CSS、相片和几行 JavaScript 代码。需要你来编写必要的 JavaScript 代码让这个项目运行起来。HTML 的 body 部分如下:</p> + +<pre class="brush: html notranslate"><h1>照片库</h1> + +<div class="full-img"> + <img class="displayed-img" src="images/pic1.jpg"> + <div class="overlay"></div> + <button class="dark">变暗</button> +</div> + +<div class="thumb-bar"> + +</div></pre> + +<p>你可以尝试操作一下这个示例,也可 <a href="https://roy-tian.github.io/mdn-examples/javascript/gallery/">在线打开</a>。(不要偷看源代码哦!)</p> + +<div class="hidden"> +<h6 id="Image_gallery">Image gallery</h6> + +<pre class="brush: html notranslate"><!DOCTYPE html> +<html> + <head> + <meta charset="utf-8"> + <style> + h1 { + font-family: helvetica, arial, sans-serif; + text-align: center; + } + + body { + width: 640px; + margin: 0 auto; + } + + .full-img { + position: relative; + display: block; + width: 640px; + height: 480px; + } + + .overlay { + position: absolute; + top: 0; + left: 0; + width: 640px; + height: 480px; + background-color: rgba(0,0,0,0); + } + + button { + background: rgba(150,150,150,0.6); + text-shadow: 1px 1px 1px white; + border: 1px solid #999; + position: absolute; + cursor: pointer; + top: 2px; + left: 2px; + } + + .thumb-bar img { + display: block; + width: 20%; + float: left; + cursor: pointer; + } + </style> + </head> + + <body> + <h1>照片库</h1> + + <div class="full-img"> + <img class="displayed-img" src="https://roy-tian.github.io/mdn-examples/gallery/images/pic1.jpg"> + <div class="overlay"></div> + <button class="dark">变暗</button> + </div> + + <div class="thumb-bar"> </div> + <script> + var displayedImage = document.querySelector('.displayed-img'); + var thumbBar = document.querySelector('.thumb-bar'); + + btn = document.querySelector('button'); + var overlay = document.querySelector('.overlay'); + + for(var i = 1; i <= 5; i++) { + var newImage = document.createElement('img'); + newImage.setAttribute('src', 'https://roy-tian.github.io/mdn-examples/gallery/images/pic' + i + '.jpg'); + thumbBar.appendChild(newImage); + newImage.onclick = function(e) { + var imgSrc = e.target.getAttribute('src'); + displayImage(imgSrc); + } + } + + function displayImage(imgSrc) { + displayedImage.setAttribute('src', imgSrc); + } + + btn.onclick = function() { + var btnClass = btn.getAttribute('class'); + if(btnClass === 'dark') { + btn.setAttribute('class','light'); + btn.textContent = '变亮'; + overlay.style.backgroundColor = 'rgba(0,0,0,0.5)'; + } else { + btn.setAttribute('class','dark'); + btn.textContent = '变暗'; + overlay.style.backgroundColor = 'rgba(0,0,0,0)'; + } + } + </script> + </body> +</html></pre> +</div> + +<ul> +</ul> + +<p>{{ EmbedLiveSample('Image_gallery', '100%', 680, "", "", "hide-codepen-jsfiddle") }}</p> + +<p>以下是本例中 CSS 文件最值得关注的部分:</p> + +<ul> + <li><code>full-img <div></code> 中有三个绝对定位的元素:一个显示全尺寸图片的 <code><img></code>,一个空 <code><div></code>(覆盖在 <code><img></code> 之上,且与之大小相同,用来设置半透明背景色来使图片变暗),和一个用来控制变暗效果的 <code><button></code>。</li> + <li>将 <code>thumb-bar <div></code> 中图片(即“缩略图”)的宽度设置为20%,并且将它们浮动至左端,使得它们在同一行上依次排列。</li> +</ul> + +<p>你的 JavaScript 需要:</p> + +<ul> + <li>遍历所有相片,为每张相片生成一个 <code><img></code> 元素并把它们插入 <code>thumb-bar <div></code> 中,这样图片就会嵌入页面。</li> + <li>为 <code>thumb-bar <div></code> 里的每个 <code><img></code> 元素添加一个 <code>onclick</code> 处理器,在图片被点击时相应的图片被显示到 <code>displayed-img <img></code> 元素上。</li> + <li>给 <code><button></code> 元素添加一个 <code>onclick</code> 处理器,当按钮被点击时,将全尺寸图片变暗,再次点击时取消。</li> +</ul> + +<p>可以看一下 <a class="external external-icon" href="https://roy-tian.github.io/learning-area/javascript/building-blocks/gallery/">完成的示例</a> 体会一下。(别偷看代码哦)</p> + +<h2 id="步骤">步骤</h2> + +<p>以下是你的工作。</p> + +<h3 id="遍历照片">遍历照片</h3> + +<p>我们提供的代码中用一个名为 <code>thumBar</code> 的变量用来存储 <code>thumb-bar <div></code> 的引用,创建了一个新的 <code><img></code> 元素,将它的 <code>src</code> 属性值设置成 <code>xxx</code> 占位符,并且将这个新的 <code><img></code> 元素添加到 <code>thumbBar</code> 里。</p> + +<p>你应该:</p> + +<ol> + <li>在"遍历图片"注释下方添加一个循环来遍历 5 张图片,只需要遍历 5 个数字,每个数字代表一张图片。</li> + <li>每次迭代中,用图片路径的字符串替换掉占位符 <code>xxx</code>。即在每次迭代中把 <code>src</code> 属性设置为图片的路径。记住,图片都在 images 目录下,文件名是 <code>pic1.jpg</code><font face="Open Sans, arial, x-locale-body, sans-serif">、</font><code>pic2.jpg</code>,等等。</li> +</ol> + +<h3 id="给每一个缩略图添加点击处理器">给每一个缩略图添加点击处理器</h3> + +<p>每次迭代中,你需要给当前的 <code>newImage</code> 加上一个 <code>onclick</code> 事件处理函数——它应该:</p> + +<ol> + <li>找到当前图片的 <code>src</code> 属性值。这个可以通过对当前的 <code><img></code> 用 <code>"src"</code> 作为参数调用 <code><a href="/zh-CN/docs/Web/API/Element/getAttribute">getAttribute()</a></code> 函数来完成,但是如何在代码里获取图片?用 <code>newImage</code> 是不行的,因为在事件处理函数应用之前循环已经结束,这样每次迭代 <code>src</code> 的值都会是最后一张图片。因此,对于每个事件处理器,<code><img></code> 都是函数的目标。是否可以从事件对象获得相关信息呢。</li> + <li>调用一个函数,取上一步返回的 <code>src</code> 值作为参数。可以给这个函数起一个喜欢的名字。</li> + <li>事件处理器函数应该把 <code>displayed-img <img></code> 的 <code>src</code> 属性值设为作为参数传入的 <code>src</code> 值。我们已经提供了一个 <code>displayedImg</code> 变量存储相关的 <code><img></code>。注意我们需要的是一个定义好的、有名字的函数。</li> +</ol> + +<h3 id="为变亮变暗按钮编写处理器">为变亮/变暗按钮编写处理器</h3> + +<p>还剩最后的变亮/变暗 <code><button></code>。我们已经提供了一个名为 <code>btn</code> 的变量来存储 <code><button></code> 的引用。需要添加一个 <code>onclick</code> 事件处理函数:</p> + +<ol> + <li>检查当前 <code><button></code> 按钮的类名称,仍可用 <code>getAttribute()</code> 函数取得。</li> + <li>如果类名的值是 <code>"dark"</code>, 将 <code><button></code> 的类名变为 <code>"light"</code>(使用 <code><a href="https://developer.mozilla.org/zh-CN/docs/Web/API/Element/setAttribute">setAttribute()</a></code>), 文本内容变为 "变亮",蒙板 <code><div></code> 的{{cssxref("background-color")}} 设为 <code>"rgba(0,0,0,0.5)"</code>。</li> + <li>如果类名的值不是 <code>"dark"</code>, 将 <code><button></code> 的类名变为 <code>"dark"</code>,文本内容变为 "变暗",蒙板 <code><div></code> 的{{cssxref("background-color")}} 设为 <code>"rgba(0,0,0,0)"</code>。</li> +</ol> + +<p>以下是实现上述 2、3 点所提功能的基本代码:</p> + +<pre class="brush: js notranslate">btn.setAttribute('class', xxx); +btn.textContent = xxx; +overlay.style.backgroundColor = xxx;</pre> + +<h2 id="提示">提示</h2> + +<ul> + <li>完全不需要修改 HTML 和 CSS 文件。</li> +</ul> + +<h2 id="测验">测验</h2> + +<p>如果你是在课堂上进行这个测验,你可以把作品交给导或教授去打分了。如果你是在自学,可以很容易地在 <a href="https://discourse.mozilla.org/t/image-gallery-assessment/24687">本节测验的讨论页</a> 或 <a href="https://wiki.mozilla.org/IRC" rel="noopener">Mozilla 聊天室</a>的 <a href="irc://irc.mozilla.org/mdn">#mdn</a> 频道回复得到批改指南。请先自己试着做,作弊学不到任何东西!</p> + +<p>{{PreviousMenu("Learn/JavaScript/Building_blocks/Events", "Learn/JavaScript/Building_blocks")}}</p> + +<h2 id="本章目录">本章目录</h2> + +<ul> + <li><a href="https://developer.mozilla.org/zh-CN/docs/Learn/JavaScript/Building_blocks/conditionals">条件语句:在代码中作出决策</a></li> + <li><a href="https://developer.mozilla.org/zh-CN/docs/Learn/JavaScript/Building_blocks/Looping_code">循环代码</a></li> + <li><a href="https://developer.mozilla.org/zh-CN/docs/Learn/JavaScript/Building_blocks/Functions">函数:可复用的代码块</a></li> + <li><a href="https://developer.mozilla.org/zh-CN/docs/Learn/JavaScript/Building_blocks/Build_your_own_function">创建自己的函数</a></li> + <li><a href="https://developer.mozilla.org/zh-CN/docs/Learn/JavaScript/Building_blocks/Return_values">函数的返回值</a></li> + <li><a href="https://developer.mozilla.org/zh-CN/docs/Learn/JavaScript/Building_blocks/Events">初识“事件”</a></li> + <li><a href="https://developer.mozilla.org/zh-CN/docs/Learn/JavaScript/Building_blocks/Image_gallery">照片库</a></li> +</ul> |