使用 JSON

JavaScript 对象表示法 (JSON) 是一种基于 JavaScript 对象语法表示结构化数据的标准文本格式。它通常用于在 Web 应用程序中传输数据(例如,将一些数据从服务器发送到客户端,以便在网页上显示,反之亦然)。您会经常遇到它,因此在本文中,我们为您提供了使用 JavaScript 处理 JSON 所需的所有内容,包括解析 JSON 以便您可以访问其中的数据,以及创建 JSON。

先决条件 对 HTML 和 CSS 的基本了解,熟悉 JavaScript 基础知识(参见 第一步构建块)以及 OOJS 基础知识(参见 对象简介)。
目标 了解如何处理存储在 JSON 中的数据,以及创建您自己的 JSON 字符串。

不,真的,什么是 JSON?

JSON 是一种基于文本的数据格式,遵循 JavaScript 对象语法,由 道格拉斯·克罗克福德 推广。尽管它与 JavaScript 对象字面量语法非常相似,但它可以独立于 JavaScript 使用,并且许多编程环境都具有读取(解析)和生成 JSON 的能力。

JSON 存在于字符串中——当您想要跨网络传输数据时非常有用。当您想要访问数据时,需要将其转换为本机 JavaScript 对象。这不是什么大问题——JavaScript 提供了一个全局 JSON 对象,其中包含用于在两者之间转换的方法。

注意:将字符串转换为本机对象称为反序列化,而将本机对象转换为字符串以便能够跨网络传输则称为序列化

JSON 字符串可以存储在它自己的文件中,该文件基本上只是一个扩展名为 .jsonMIME 类型application/json 的文本文件。

JSON 结构

如上所述,JSON 是一个字符串,其格式非常类似于 JavaScript 对象字面量格式。您可以在 JSON 中包含与标准 JavaScript 对象中相同的基本数据类型——字符串、数字、数组、布尔值和其他对象字面量。这允许您构建数据层次结构,如下所示

json
{
  "squadName": "Super hero squad",
  "homeTown": "Metro City",
  "formed": 2016,
  "secretBase": "Super tower",
  "active": true,
  "members": [
    {
      "name": "Molecule Man",
      "age": 29,
      "secretIdentity": "Dan Jukes",
      "powers": ["Radiation resistance", "Turning tiny", "Radiation blast"]
    },
    {
      "name": "Madame Uppercut",
      "age": 39,
      "secretIdentity": "Jane Wilson",
      "powers": [
        "Million tonne punch",
        "Damage resistance",
        "Superhuman reflexes"
      ]
    },
    {
      "name": "Eternal Flame",
      "age": 1000000,
      "secretIdentity": "Unknown",
      "powers": [
        "Immortality",
        "Heat Immunity",
        "Inferno",
        "Teleportation",
        "Interdimensional travel"
      ]
    }
  ]
}

例如,如果我们将此字符串加载到 JavaScript 程序中并将其解析到名为 superHeroes 的变量中,那么我们就可以使用我们在 JavaScript 对象基础知识 文章中看到的相同的点/括号表示法来访问其中的数据。例如

js
superHeroes.homeTown;
superHeroes["active"];

要访问层次结构中更深层的数据,您必须将所需的属性名称和数组索引链接在一起。例如,要访问成员列表中第二个英雄的第三个超能力,您可以执行以下操作

js
superHeroes["members"][1]["powers"][2];
  1. 首先,我们有变量名——superHeroes
  2. 在其中,我们想访问 members 属性,所以我们使用 ["members"]
  3. members 包含一个由对象填充的数组。我们想访问数组中的第二个对象,所以我们使用 [1]
  4. 在此对象中,我们想访问 powers 属性,所以我们使用 ["powers"]
  5. powers 属性中包含一个数组,其中包含所选英雄的超能力。我们想要第三个,所以我们使用 [2]

注意:我们在 JSONTest.html 示例中(参见 源代码)的变量中提供了上面看到的 JSON。尝试加载它,然后通过浏览器的 JavaScript 控制台访问变量中的数据。

数组作为 JSON

上面我们提到 JSON 文本基本上看起来像字符串中的 JavaScript 对象。我们还可以将数组转换为 JSON 或从 JSON 转换。例如,下面也是有效的 JSON

json
[
  {
    "name": "Molecule Man",
    "age": 29,
    "secretIdentity": "Dan Jukes",
    "powers": ["Radiation resistance", "Turning tiny", "Radiation blast"]
  },
  {
    "name": "Madame Uppercut",
    "age": 39,
    "secretIdentity": "Jane Wilson",
    "powers": [
      "Million tonne punch",
      "Damage resistance",
      "Superhuman reflexes"
    ]
  }
]

以上是完全有效的 JSON。您只需要从数组索引开始访问数组项(在其解析版本中),例如 [0]["powers"][0]

其他说明

  • JSON 纯粹是一个具有指定数据格式的字符串——它只包含属性,不包含方法。
  • JSON 要求在字符串和属性名称周围使用双引号。除了围绕整个 JSON 字符串之外,单引号无效。
  • 即使是一个错位的逗号或冒号也会导致 JSON 文件出错,无法工作。您应该小心验证您尝试使用的任何数据(尽管计算机生成的 JSON 出现错误的可能性较小,只要生成器程序工作正常)。您可以使用 JSONLint 等应用程序验证 JSON。
  • JSON 实际上可以采用任何对包含在 JSON 中有效的任何数据类型,而不仅仅是数组或对象。因此,例如,单个字符串或数字将是有效的 JSON。
  • 与 JavaScript 代码中对象属性可以不带引号不同,在 JSON 中,只有带引号的字符串可以用作属性。

主动学习:完成 JSON 示例

因此,让我们通过一个示例来演示如何在网站上使用一些 JSON 格式的数据。

入门

首先,创建我们 heroes.htmlstyle.css 文件的本地副本。后者包含一些简单的 CSS 来设置页面的样式,而前者包含一些非常简单的正文 HTML,以及一个 <script> 元素,用于包含我们将在本练习中编写的 JavaScript 代码

html
<header>
...
</header>

<section>
...
</section>

<script>
...
</script>

我们已在 GitHub 上提供了我们的 JSON 数据,网址为 https://mdn.github.io/learning-area/javascript/oojs/json/superheroes.json

我们将 JSON 加载到我们的脚本中,并使用一些巧妙的 DOM 操作来显示它,如下所示

Image of a document titled "Super hero squad" (in a fancy font) and subtitled "Hometown: Metro City // Formed: 2016". Three columns below the heading are titled "Molecule Man", "Madame Uppercut", and "Eternal Flame", respectively. Each column lists the hero's secret identity name, age, and superpowers.

顶级函数

顶级函数如下所示

js
async function populate() {
  const requestURL =
    "https://mdn.github.io/learning-area/javascript/oojs/json/superheroes.json";
  const request = new Request(requestURL);

  const response = await fetch(request);
  const superHeroes = await response.json();

  populateHeader(superHeroes);
  populateHeroes(superHeroes);
}

为了获取 JSON,我们使用了一个名为 Fetch 的 API。此 API 允许我们通过 JavaScript 发出网络请求以从服务器检索资源(例如图像、文本、JSON,甚至 HTML 片段),这意味着我们可以在不重新加载整个页面的情况下更新少量内容。

在我们的函数中,前四行使用 Fetch API 从服务器获取 JSON

  • 我们声明 requestURL 变量来存储 GitHub URL
  • 我们使用 URL 初始化一个新的 Request 对象。
  • 我们使用 fetch() 函数发出网络请求,这将返回一个 Response 对象
  • 我们使用 Response 对象的 json() 函数以 JSON 格式检索响应。

注意:fetch() API 是异步的。我们将在 下一个模块 中详细了解异步函数,但现在,我们只说我们需要在使用 fetch API 的函数名称之前添加关键字 async,并在对任何异步函数的调用之前添加关键字 await

在所有这些之后,superHeroes 变量将包含基于 JSON 的 JavaScript 对象。然后,我们将该对象传递给两个函数调用——第一个函数使用正确的数据填充 <header>,而第二个函数为团队中的每个英雄创建一个信息卡,并将其插入 <section> 中。

填充标题

现在我们已经检索了 JSON 数据并将其转换为 JavaScript 对象,让我们通过编写上面提到的两个函数来使用它。首先,在之前的代码下方添加以下函数定义

js
function populateHeader(obj) {
  const header = document.querySelector("header");
  const myH1 = document.createElement("h1");
  myH1.textContent = obj.squadName;
  header.appendChild(myH1);

  const myPara = document.createElement("p");
  myPara.textContent = `Hometown: ${obj.homeTown} // Formed: ${obj.formed}`;
  header.appendChild(myPara);
}

在这里,我们首先使用 createElement() 创建一个 h1 元素,将其 textContent 设置为等于对象的 squadName 属性,然后使用 appendChild() 将其附加到标题。然后,我们对段落执行非常类似的操作:创建它,设置其文本内容并将其附加到标题。唯一的区别是它的文本设置为包含对象的 homeTownformed 属性的 模板字面量

创建英雄信息卡

接下来,在代码底部添加以下函数,该函数创建并显示超级英雄卡片

js
function populateHeroes(obj) {
  const section = document.querySelector("section");
  const heroes = obj.members;

  for (const hero of heroes) {
    const myArticle = document.createElement("article");
    const myH2 = document.createElement("h2");
    const myPara1 = document.createElement("p");
    const myPara2 = document.createElement("p");
    const myPara3 = document.createElement("p");
    const myList = document.createElement("ul");

    myH2.textContent = hero.name;
    myPara1.textContent = `Secret identity: ${hero.secretIdentity}`;
    myPara2.textContent = `Age: ${hero.age}`;
    myPara3.textContent = "Superpowers:";

    const superPowers = hero.powers;
    for (const power of superPowers) {
      const listItem = document.createElement("li");
      listItem.textContent = power;
      myList.appendChild(listItem);
    }

    myArticle.appendChild(myH2);
    myArticle.appendChild(myPara1);
    myArticle.appendChild(myPara2);
    myArticle.appendChild(myPara3);
    myArticle.appendChild(myList);

    section.appendChild(myArticle);
  }
}

首先,我们将 JavaScript 对象的 members 属性存储在一个新变量中。此数组包含多个包含每个英雄信息的 对象。

接下来,我们使用 for...of 循环 遍历数组中的每个对象。对于每个对象,我们

  1. 创建几个新元素:一个 <article>、一个 <h2>、三个 <p> 和一个 <ul>
  2. <h2> 设置为包含当前英雄的 name
  3. 使用他们的 secretIdentityage 和一行“超能力:”来填充三个段落,以介绍列表中的信息。
  4. powers 属性存储在另一个名为 superPowers 的新常量中——它包含一个列出当前英雄超能力的数组。
  5. 使用另一个 for...of 循环遍历当前英雄的超能力——对于每个超能力,我们创建一个 <li> 元素,将超能力放入其中,然后使用 appendChild()listItem 放入 <ul> 元素(myList)中。
  6. 我们做的最后一件事是将 <h2><p><ul> 附加到 <article>myArticle)中,然后将 <article> 附加到 <section> 中。附加事物的顺序很重要,因为这是它们在 HTML 中显示的顺序。

注意:如果您在使示例工作时遇到问题,请尝试参考我们的 heroes-finished.html 源代码(也可以查看 在线运行 的代码)。

注意:如果您在理解我们用于访问 JavaScript 对象的点/括号表示法时遇到困难,可以尝试在另一个标签页或文本编辑器中打开superheroes.json文件,并在查看 JavaScript 代码时参考它。您还可以参考我们的JavaScript 对象基础文章,以获取有关点和括号表示法的更多信息。

调用顶级函数

最后,我们需要调用我们的顶级populate()函数

js
populate();

在对象和文本之间转换

以上示例在访问 JavaScript 对象方面很简单,因为我们使用response.json()将网络响应直接转换为 JavaScript 对象。

但有时我们没那么幸运——有时我们会收到原始的 JSON 字符串,我们需要自己将其转换为对象。当我们想要通过网络发送 JavaScript 对象时,需要在发送之前将其转换为 JSON(字符串)。幸运的是,这两个问题在 Web 开发中非常常见,浏览器中提供了一个内置的JSON对象,其中包含以下两种方法

  • parse():接受 JSON 字符串作为参数,并返回相应的 JavaScript 对象。
  • stringify():接受对象作为参数,并返回等效的 JSON 字符串。

您可以在我们的heroes-finished-json-parse.html示例中看到第一个方法的应用(参见源代码)——它与我们之前构建的示例完全相同,只是

  • 我们通过调用响应的text()方法,以文本而不是 JSON 的形式检索响应
  • 然后我们使用parse()将文本转换为 JavaScript 对象。

关键代码片段如下所示

js
async function populate() {
  const requestURL =
    "https://mdn.github.io/learning-area/javascript/oojs/json/superheroes.json";
  const request = new Request(requestURL);

  const response = await fetch(request);
  const superHeroesText = await response.text();

  const superHeroes = JSON.parse(superHeroesText);
  populateHeader(superHeroes);
  populateHeroes(superHeroes);
}

正如您可能猜到的,stringify()的工作方式相反。尝试逐一将以下几行代码输入到浏览器的 JavaScript 控制台中,以查看其运行效果

js
let myObj = { name: "Chris", age: 38 };
myObj;
let myString = JSON.stringify(myObj);
myString;

这里我们创建了一个 JavaScript 对象,然后检查其内容,然后使用stringify()将其转换为 JSON 字符串——将返回值保存在一个新变量中——然后再次检查它。

测试你的技能!

您已经阅读完了本文,但您还记得最重要的信息吗?在继续学习之前,您可以进行一些额外的测试来验证您是否掌握了这些信息——请参阅测试您的技能:JSON

总结

在本文中,我们为您提供了使用 JSON 进行编程的简单指南,包括如何创建和解析 JSON,以及如何访问其中包含的数据。在下一篇文章中,我们将开始学习面向对象的 JavaScript。

另请参阅