什么是 JavaScript?

欢迎来到 MDN JavaScript 初学者课程! 在本文中,我们将从更高的层次了解 JavaScript,回答诸如“它是什么?”和“你能用它做什么?”之类的问题,并确保您对 JavaScript 的用途感到满意。

先决条件 对 HTML 和 CSS 的基本了解。
目标 熟悉 JavaScript 是什么,它能做什么以及它如何融入网站。

高级定义

JavaScript 是一种脚本或编程语言,它允许您在网页上实现复杂的特性——每当一个网页不仅仅是停在那里显示静态信息供您查看时——显示及时内容更新、交互式地图、动画 2D/3D 图形、滚动视频点播器等——您可以肯定 JavaScript 很可能参与其中。它是标准 Web 技术层蛋糕的第三层,其中两层(HTMLCSS)我们在学习区域的其他部分中进行了更详细的介绍。

The three layers of standard web technologies; HTML, CSS and JavaScript

  • HTML 是我们用来构建和赋予 Web 内容意义的标记语言,例如定义段落、标题和数据表格,或者在页面中嵌入图像和视频。
  • CSS 是一种样式规则语言,我们使用它来为 HTML 内容应用样式,例如设置背景颜色和字体,以及将内容布局在多个列中。
  • JavaScript 是一种脚本语言,它使您能够创建动态更新的内容、控制多媒体、动画图像以及几乎所有其他内容。(好吧,不是所有内容,但使用几行 JavaScript 代码就能实现令人惊叹的事情。)

这三层很好地相互构建。让我们以按钮为例。我们可以使用 HTML 对其进行标记以赋予其结构和目的

html
<button type="button">Player 1: Chris</button>

Button showing Player 1: Chris with no styling

然后,我们可以将一些 CSS 添加到其中,使其看起来更漂亮

css
button {
  font-family: "helvetica neue", helvetica, sans-serif;
  letter-spacing: 1px;
  text-transform: uppercase;
  border: 2px solid rgb(200 200 0 / 60%);
  background-color: rgb(0 217 217 / 60%);
  color: rgb(100 0 0 / 100%);
  box-shadow: 1px 1px 2px rgb(0 0 200 / 40%);
  border-radius: 10px;
  padding: 3px 10px;
  cursor: pointer;
}

Button showing Player 1: Chris with styling

最后,我们可以添加一些 JavaScript 来实现动态行为

js
const button = document.querySelector("button");

button.addEventListener("click", updateName);

function updateName() {
  const name = prompt("Enter a new name");
  button.textContent = `Player 1: ${name}`;
}

尝试单击文本标签的最后一个版本,看看会发生什么(还要注意,您可以在 GitHub 上找到此演示——查看 源代码,或 在线运行)!

JavaScript 可以做的不仅仅是这些——让我们更详细地探讨一下。

它到底能做什么?

核心客户端 JavaScript 语言包含一些常见的编程功能,这些功能允许您执行以下操作

  • 将有用的值存储在变量中。例如,在上面的示例中,我们要求输入一个新的姓名,然后将该姓名存储在名为 name 的变量中。
  • 对文本片段(在编程中称为“字符串”)进行操作。在上面的示例中,我们将字符串“玩家 1:”与 name 变量连接起来,创建完整的文本标签,例如“玩家 1:Chris”。
  • 响应网页上发生的某些事件运行代码。我们在上面的示例中使用了一个 click 事件来检测何时单击标签,然后运行更新文本标签的代码。
  • 以及更多!

更令人兴奋的是构建在客户端 JavaScript 语言之上的功能。所谓的 **应用程序编程接口**(**API**)为您提供了在 JavaScript 代码中使用的额外超能力。

API 是现成的代码构建块集合,允许开发人员实现原本很难或不可能实现的程序。它们对编程的作用与现成家具套件对房屋建造的作用相同——将现成切割的板子螺在一起制作书架比自己设计、去寻找合适的木材、将所有板子切割成正确的尺寸和形状、找到合适的尺寸螺丝,然后将它们组装在一起制作书架要容易得多。

它们通常分为两类。

Two categories of API; 3rd party APIs are shown to the side of the browser and browser APIs are in the browser

**浏览器 API** 内置于您的 Web 浏览器中,并且能够公开来自周围计算机环境的数据,或执行有用的复杂操作。例如

  • DOM(文档对象模型)API 允许您操作 HTML 和 CSS,创建、删除和更改 HTML,动态地将新样式应用于您的页面等。每次您在页面上看到弹出窗口出现,或显示一些新内容(如我们在上面的简单演示中看到的那样)时,都是 DOM 在起作用。
  • 地理位置 API 检索地理信息。这就是 Google 地图 能够找到您的位置并将其绘制在地图上的方式。
  • CanvasWebGL API 允许您创建动画 2D 和 3D 图形。人们正在使用这些 Web 技术做一些令人惊叹的事情——请参阅 Chrome 实验webglsamples
  • 音频和视频 API(如 HTMLMediaElementWebRTC)允许您对多媒体做一些非常有趣的事情,例如在网页中播放音频和视频,或者从您的网络摄像头获取视频并在其他人的计算机上显示它(尝试我们简单的 Snapshot 演示,了解一下)。

**注意:** 上述许多演示在较旧的浏览器中将无法正常工作——在进行实验时,最好使用现代浏览器(如 Firefox、Chrome、Edge 或 Opera)来运行您的代码。在您更接近交付生产代码时(即真正的客户将使用的真实代码),您将需要更详细地考虑 跨浏览器测试

**第三方 API** 默认情况下不会内置到浏览器中,您通常需要从 Web 上的某个地方获取它们的代码和信息。例如

**注意:** 这些 API 很高级,我们不会在本模块中介绍任何这些 API。您可以在我们的 客户端 Web API 模块 中找到更多有关这些 API 的信息。

还有更多可用!但是,现在不要太兴奋。在学习 JavaScript 24 小时后,您将无法构建下一个 Facebook、Google 地图或 Instagram——有很多基础知识需要首先学习。这就是您来到这里的原因——让我们继续吧!

JavaScript 在您的页面上做什么?

在这里,我们将开始实际查看一些代码,并在查看代码的同时,探索在页面中运行一些 JavaScript 时实际发生了什么。

让我们简要回顾一下在浏览器中加载网页时发生的事情(首先在我们的 CSS 如何工作 文章中讨论)。当您在浏览器中加载网页时,您是在执行环境(浏览器选项卡)中运行您的代码(HTML、CSS 和 JavaScript)。这就像一个工厂,它接收原材料(代码)并输出产品(网页)。

HTML, CSS and JavaScript code come together to create the content in the browser tab when the page is loaded

JavaScript 的一个非常常见的用途是通过文档对象模型 API(如上所述)动态地修改 HTML 和 CSS 以更新用户界面。

浏览器安全

每个浏览器选项卡都有自己的单独区域来运行代码(在技术术语中,这些区域称为“执行环境”)——这意味着在大多数情况下,每个选项卡中的代码都是完全独立运行的,并且一个选项卡中的代码不能直接影响另一个选项卡中的代码——或另一个网站上的代码。这是一个很好的安全措施——如果没有这个,海盗就可以开始编写代码来窃取其他网站的信息,以及其他此类坏事。

**注意:** 有些方法可以以安全的方式在不同的网站/选项卡之间发送代码和数据,但这些都是我们不会在本课程中介绍的高级技术。

JavaScript 运行顺序

当浏览器遇到一段 JavaScript 代码时,它通常会按顺序从上到下运行它。这意味着您需要小心放置代码的顺序。例如,让我们回到我们第一个示例中看到的 JavaScript 代码块

js
const button = document.querySelector("button");

button.addEventListener("click", updateName);

function updateName() {
  const name = prompt("Enter a new name");
  button.textContent = `Player 1: ${name}`;
}

在这里,我们首先使用 document.querySelector 选择一个按钮,然后使用 addEventListener 为其附加一个事件监听器,以便当单击按钮时,运行 updateName() 代码块(第 5-8 行)。updateName() 代码块(这些类型的可重用代码块称为“函数”)询问用户一个新的姓名,然后将该姓名插入按钮文本中以更新显示。

如果您交换前两行代码的顺序,它将不再起作用——相反,您将在 浏览器开发者控制台 中收到一个错误——未捕获的 ReferenceError:在初始化之前无法访问 'button'。这意味着 button 对象尚未初始化,因此我们无法为其添加事件监听器。

**注意:** 这是一个非常常见的错误——您需要确保代码中引用的对象在您尝试对它们执行操作之前存在。

解释型代码与编译型代码

您可能会在编程上下文中听到 **解释型** 和 **编译型** 术语。在解释型语言中,代码从上到下运行,运行代码的结果立即返回。您不必将代码转换为另一种形式,然后浏览器才能运行它。代码以程序员友好的文本形式接收,并直接从该形式进行处理。

另一方面,编译型语言在由计算机运行之前会被转换为另一种形式(编译)。例如,C/C++ 会被编译成机器代码,然后由计算机运行。程序从二进制格式执行,该二进制格式是从原始程序源代码生成的。

JavaScript 是一种轻量级的解释型编程语言。Web 浏览器以其原始文本形式接收 JavaScript 代码,并从该形式运行脚本。从技术角度讲,大多数现代 JavaScript 解释器实际上使用一种称为 **即时编译** 的技术来提高性能;JavaScript 源代码在脚本使用时被编译成更快的二进制格式,以便能够尽快运行。但是,JavaScript 仍然被认为是一种解释型语言,因为编译是在运行时处理的,而不是在运行之前处理的。

两种类型的语言都有优点,但我们现在不讨论它们。

服务器端代码与客户端代码

你可能还会听到服务器端客户端代码这两个术语,尤其是在 Web 开发的语境中。客户端代码是在用户计算机上运行的代码——当浏览网页时,网页的客户端代码会被下载,然后由浏览器运行和显示。在本模块中,我们明确地讨论的是客户端 JavaScript

另一方面,服务器端代码在服务器上运行,然后它的结果被下载并在浏览器中显示。流行的服务器端 Web 语言的示例包括 PHP、Python、Ruby、ASP.NET,甚至 JavaScript!JavaScript 也可以用作服务器端语言,例如在流行的 Node.js 环境中——你可以在我们的动态网站 – 服务器端编程主题中了解更多关于服务器端 JavaScript 的信息。

动态代码与静态代码

动态这个词用于描述客户端 JavaScript 和服务器端语言——它指的是在不同情况下更新网页/应用程序显示以显示不同内容的能力,根据需要生成新内容。服务器端代码动态地在服务器上生成新内容,例如从数据库中提取数据,而客户端 JavaScript 动态地在客户端的浏览器中生成新内容,例如创建一个新的 HTML 表格,用从服务器请求的数据填充它,然后在显示给用户的网页中显示表格。这两个上下文中的含义略有不同,但相关联,并且两种方法(服务器端和客户端)通常协同工作。

没有动态更新内容的网页被称为静态——它总是显示相同的内容。

如何将 JavaScript 添加到您的页面?

JavaScript 应用于你的 HTML 页面,类似于 CSS 的应用方式。CSS 使用<link>元素应用外部样式表,使用<style>元素将内部样式表应用于 HTML,而 JavaScript 在 HTML 世界中只需要一个朋友——<script>元素。让我们学习一下它是如何工作的。

内部 JavaScript

  1. 首先,制作示例文件apply-javascript.html的本地副本。将其保存在某个合理的目录中。
  2. 在你的 Web 浏览器和文本编辑器中打开文件。你会看到 HTML 创建了一个包含可点击按钮的简单网页。
  3. 接下来,转到你的文本编辑器,并将以下内容添加到你的 body 底部——就在你的结束</body>标签之前
    html
    <script>
      // JavaScript goes here
    </script>
    
    请注意,你的 Web 文档中的代码通常按照它在页面上出现的顺序加载和执行。通过将 JavaScript 放置在底部,我们确保所有 HTML 元素都已加载。(另请参阅下面脚本加载策略。)
  4. 现在,我们将添加一些 JavaScript 代码到我们的<script>元素中,使页面做一些更有趣的事情——将以下代码添加到 "// JavaScript goes here" 行的下方
    js
    function createParagraph() {
      const para = document.createElement("p");
      para.textContent = "You clicked the button!";
      document.body.appendChild(para);
    }
    
    const buttons = document.querySelectorAll("button");
    
    for (const button of buttons) {
      button.addEventListener("click", createParagraph);
    }
    
  5. 保存你的文件并刷新浏览器——现在你应该看到,当你点击按钮时,会生成一个新段落并放置在下方。

注意:如果你的示例似乎无法正常工作,请再次执行这些步骤并检查你是否做对了所有步骤。你是否将开始代码的本地副本保存为.html文件?你是否在</body>标签之前添加了你的<script>元素?你是否完全按照所示输入了 JavaScript 代码?JavaScript 区分大小写,并且非常挑剔,因此你必须完全按照所示输入语法,否则它可能无法正常工作。

注意:你可以在 GitHub 上看到此版本,即apply-javascript-internal.html也可以查看实时版本)。

外部 JavaScript

这效果很好,但是如果我们想将我们的 JavaScript 代码放在一个外部文件中呢?现在让我们探索一下。

  1. 首先,在你的示例 HTML 文件所在的同一个目录中创建一个新文件。将其命名为script.js——确保它具有该 .js 文件扩展名,因为这样它才能被识别为 JavaScript 代码。
  2. 删除你当前在</body>底部<script>元素,并在结束</head>标签之前添加以下内容(这样浏览器就可以比它在底部时更早地开始加载文件)
    html
    <script type="module" src="script.js"></script>
    
  3. script.js中,添加以下脚本
    js
    function createParagraph() {
      const para = document.createElement("p");
      para.textContent = "You clicked the button!";
      document.body.appendChild(para);
    }
    
    const buttons = document.querySelectorAll("button");
    
    for (const button of buttons) {
      button.addEventListener("click", createParagraph);
    }
    
  4. 保存并刷新你的浏览器。你会发现点击按钮没有效果,并且如果你检查浏览器的控制台,你会看到一个类似于Cross-origin request blocked的错误。这是因为像许多外部资源一样,JavaScript 模块需要从与 HTML相同来源加载,而file:// URL 不符合要求。有两个解决方案可以解决这个问题
    • 我们推荐的解决方案是按照设置本地测试服务器的指南进行操作。在服务器程序运行并在端口8000上提供apply-javascript-external.htmlscript.js文件后,打开你的浏览器并访问https://127.0.0.1:8000
    • 如果你无法运行本地服务器,你也可以使用<script defer src="script.js"></script>而不是<script type="module" src="script.js"></script>。有关更多信息,请参阅下面的脚本加载策略。但请注意,我们在本教程的其他部分中使用的功能可能仍然需要本地 HTTP 服务器。
  5. 现在网站的工作原理与以前完全相同,但现在我们将 JavaScript 代码放在了外部文件中。从组织代码和使它在多个 HTML 文件中可重用方面来看,这通常是一件好事。此外,没有大块脚本代码倾倒在 HTML 中,HTML 更易于阅读。

注意:你可以在 GitHub 上看到此版本,即apply-javascript-external.htmlscript.js也可以查看实时版本)。

内联 JavaScript 处理程序

请注意,有时你会在 HTML 中看到一些实际的 JavaScript 代码。它可能看起来像这样

js
function createParagraph() {
  const para = document.createElement("p");
  para.textContent = "You clicked the button!";
  document.body.appendChild(para);
}
html
<button onclick="createParagraph()">Click me!</button>

你可以在下面尝试此版本的演示。

此演示与前两节中的功能完全相同,只是<button>元素包含一个内联onclick处理程序,以便在按下按钮时运行该函数。

但是,请不要这样做。在 HTML 中使用 JavaScript 代码是一种不好的做法,而且效率低下——你必须在要应用 JavaScript 代码的每个按钮上包含onclick="createParagraph()"属性。

使用 addEventListener 替代

不要在 HTML 中包含 JavaScript 代码,而是使用纯 JavaScript 结构。querySelectorAll()函数允许你选择页面上的所有按钮。然后,你可以遍历这些按钮,使用addEventListener()为每个按钮分配一个处理程序。下面显示了此代码

js
const buttons = document.querySelectorAll("button");

for (const button of buttons) {
  button.addEventListener("click", createParagraph);
}

这可能比onclick属性稍长一些,但它适用于所有按钮——无论页面上有多少个按钮,也不管添加或删除了多少个按钮。JavaScript 代码不需要更改。

注意:尝试编辑你版本的apply-javascript.html,并在文件中添加几个按钮。当你重新加载页面时,你应该发现,所有按钮在被点击时都会创建一个段落。很酷吧?

脚本加载策略

页面上的所有 HTML 代码都按照出现的顺序加载。如果你使用 JavaScript 操作页面上的元素(更准确地说,是文档对象模型),那么如果 JavaScript 代码在你要对其进行操作的 HTML 代码被解析之前就被加载和解析,那么你的代码将无法正常工作。

有一些不同的策略可以确保你的 JavaScript 代码只在 HTML 代码被解析后运行

  • 在上面的内部 JavaScript 示例中,脚本元素被放置在文档 body 的底部,因此只有在解析完其余的 HTML body 后才会运行。
  • 在上面的外部 JavaScript 示例中,脚本元素被放置在文档 head 中,在解析 HTML body 之前。但由于我们使用的是<script type="module">,因此代码被视为一个模块,并且浏览器会在执行 JavaScript 模块之前等待所有 HTML 代码被处理。(你也可以将外部脚本放置在 body 的底部。但如果 HTML 代码很多,网络很慢,那么浏览器可能需要很长时间才能开始获取和加载脚本,因此将外部脚本放在 head 中通常更好。)
  • 如果你仍然想在文档 head 中使用非模块脚本,这可能会阻止整个页面显示,并且可能会导致错误,因为它在解析 HTML 代码之前执行
    • 对于外部脚本,你应该在<script>元素上添加defer属性(或者如果你不需要 HTML 代码就绪,则添加async属性)。
    • 对于内部脚本,你应该将代码包装在一个DOMContentLoaded事件监听器中。
    这超出了本教程的范围,但除非你需要支持非常旧的浏览器,否则你不必这样做,只需使用<script type="module">即可。

注释

与 HTML 和 CSS 一样,你也可以在 JavaScript 代码中编写注释,这些注释会被浏览器忽略,并且它们的存在是为了向你的开发人员同事提供有关代码工作原理的说明(以及你,如果你在六个月后回到你的代码并且不记得你做了什么)。注释非常有用,你应该经常使用它们,特别是对于较大的应用程序。有两种类型

  • 单行注释写在双斜杠 (//) 后面,例如
    js
    // I am a comment
    
  • 多行注释写在/**/字符串之间,例如
    js
    /*
      I am also
      a comment
    */
    

例如,我们可以用注释来注释我们最后一个演示的 JavaScript 代码,如下所示

js
// Function: creates a new paragraph and appends it to the bottom of the HTML body.

function createParagraph() {
  const para = document.createElement("p");
  para.textContent = "You clicked the button!";
  document.body.appendChild(para);
}

/*
  1. Get references to all the buttons on the page in an array format.
  2. Loop through all the buttons and add a click event listener to each one.

  When any button is pressed, the createParagraph() function will be run.
*/

const buttons = document.querySelectorAll("button");

for (const button of buttons) {
  button.addEventListener("click", createParagraph);
}

注意:一般来说,更多的注释通常比更少的注释更好,但是如果你发现自己添加了很多注释来解释变量是什么(你的变量名可能应该更直观),或者解释一些非常简单的操作(也许你的代码过于复杂),你应该小心。

总结

就是这样,你迈入了 JavaScript 世界的第一步。我们从理论开始,让你逐渐习惯于为什么要使用 JavaScript 以及你可以用它做什么。在此过程中,你看到了几个代码示例,并了解了 JavaScript 如何与网站上的其他代码相结合,以及其他一些内容。

JavaScript 现在可能看起来有点令人生畏,但不用担心——在本课程中,我们将以简单的步骤带你学习它,这些步骤在你接下来的学习中会很有意义。在下一篇文章中,我们将直接进入实践,让你直接开始构建自己的 JavaScript 示例。