使用 JSON

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

¥JavaScript Object Notation (JSON) is a standard text-based format for representing structured data based on JavaScript object syntax. It is commonly used for transmitting data in web applications (e.g., sending some data from the server to the client, so it can be displayed on a web page, or vice versa). You'll come across it quite often, so in this article, we give you all you need to work with JSON using JavaScript, including parsing JSON so you can access data within it, and creating JSON.

先决条件: 对 HTML 和 CSS 有基本了解,熟悉 JavaScript 基础知识(请参阅 第一步架构模块)和 OOJS 基础知识(请参阅 对象介绍)。
目标: 了解如何使用 JSON 中存储的数据,并创建你自己的 JSON 字符串。

不,真的,什么是 JSON?

¥No, really, what is JSON?

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

¥JSON is a text-based data format following JavaScript object syntax, which was popularized by Douglas Crockford. Even though it closely resembles JavaScript object literal syntax, it can be used independently from JavaScript, and many programming environments feature the ability to read (parse) and generate JSON.

JSON 以字符串形式存在 - 当你想要通过网络传输数据时很有用。当你想要访问数据时,需要将其转换为原生 JavaScript 对象。这不是一个大问题 - JavaScript 提供了一个全局 JSON 对象,该对象具有可用于在两者之间进行转换的方法。

¥JSON exists as a string — useful when you want to transmit data across a network. It needs to be converted to a native JavaScript object when you want to access the data. This is not a big issue — JavaScript provides a global JSON object that has methods available for converting between the two.

注意:将字符串转换为原生对象称为反序列化,而将原生对象转换为字符串以便可以通过网络传输称为序列化。

¥Note: Converting a string to a native object is called deserialization, while converting a native object to a string so it can be transmitted across the network is called serialization.

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

¥A JSON string can be stored in its own file, which is basically just a text file with an extension of .json, and a MIME type of application/json.

JSON 结构

¥JSON structure

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

¥As described above, JSON is a string whose format very much resembles JavaScript object literal format. You can include the same basic data types inside JSON as you can in a standard JavaScript object — strings, numbers, arrays, booleans, and other object literals. This allows you to construct a data hierarchy, like so:

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 对象基础知识 文章中查看的相同点/括号表示法来访问其中的数据。例如:

¥If we loaded this string into a JavaScript program and parsed it into a variable called superHeroes for example, we could then access the data inside it using the same dot/bracket notation we looked at in the JavaScript object basics article. For example:

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

要进一步访问层次结构中的数据,你必须将所需的属性名称和数组索引链接在一起。例如,要访问成员列表中列出的第二个英雄的第三个超级大国,你可以这样做:

¥To access data further down the hierarchy, you have to chain the required property names and array indexes together. For example, to access the third superpower of the second hero listed in the members list, you'd do this:

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

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

¥Note: We've made the JSON seen above available inside a variable in our JSONTest.html example (see the source code). Try loading this up and then accessing data inside the variable via your browser's JavaScript console.

JSON 形式的数组

¥Arrays as JSON

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

¥Above we mentioned that JSON text basically looks like a JavaScript object inside a string. We can also convert arrays to/from JSON. Below is also valid JSON, for example:

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])开始访问数组项(在其解析版本中)。

¥The above is perfectly valid JSON. You'd just have to access array items (in its parsed version) by starting with an array index, for example [0]["powers"][0].

其他注意事项

¥Other notes

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

主动学习:通过 JSON 示例进行操作

¥Active learning: Working through a JSON example

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

¥So, let's work through an example to show how we could make use of some JSON formatted data on a website.

入门

¥Getting started

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

¥To begin with, make local copies of our heroes.html and style.css files. The latter contains some simple CSS to style our page, while the former contains some very simple body HTML, plus a <script> element to contain the JavaScript code we will be writing in this exercise:

html
<header>
...
</header>

<section>
...
</section>

<script>
...
</script>

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

¥We have made our JSON data available on our GitHub, at https://mdn.github.io/learning-area/javascript/oojs/json/superheroes.json.

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

¥We are going to load the JSON into our script, and use some nifty DOM manipulation to display it, like this:

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.

顶层函数

¥Top-level function

顶层函数如下所示:

¥The top-level function looks like this:

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 片段),这意味着我们可以更新一小部分内容,而无需重新加载整个页面。

¥To obtain the JSON, we use an API called Fetch. This API allows us to make network requests to retrieve resources from a server via JavaScript (e.g. images, text, JSON, even HTML snippets), meaning that we can update small sections of content without having to reload the entire page.

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

¥In our function, the first four lines use the Fetch API to fetch the JSON from the server:

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

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

¥Note: The fetch() API is asynchronous. We'll learn a lot about asynchronous functions in the next module, but for now, we'll just say that we need to add the keyword async before the name of the function that uses the fetch API, and add the keyword await before the calls to any asynchronous functions.

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

¥After all that, the superHeroes variable will contain the JavaScript object based on the JSON. We are then passing that object to two function calls — the first one fills the <header> with the correct data, while the second one creates an information card for each hero on the team, and inserts it into the <section>.

填充标题

¥Populating the header

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

¥Now that we've retrieved the JSON data and converted it into a JavaScript object, let's make use of it by writing the two functions we referenced above. First of all, add the following function definition below the previous code:

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 属性的 模板文字

¥Here we first create an h1 element with createElement(), set its textContent to equal the squadName property of the object, then append it to the header using appendChild(). We then do a very similar operation with a paragraph: create it, set its text content and append it to the header. The only difference is that its text is set to a template literal containing both the homeTown and formed properties of the object.

创建英雄信息卡

¥Creating the hero information cards

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

¥Next, add the following function at the bottom of the code, which creates and displays the superhero cards:

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 属性存储在一个新变量中。该数组包含多个对象,其中包含每个英雄的信息。

¥To start with, we store the members property of the JavaScript object in a new variable. This array contains multiple objects that contain the information for each hero.

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

¥Next, we use a for...of loop to loop through each object in the array. For each one, we:

  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 源代码(也请参阅 实时运行。)

¥Note: If you are having trouble getting the example to work, try referring to our heroes-finished.html source code (see it running live also.)

注意:如果你在遵循我们用来访问 JavaScript 对象的点/括号表示法时遇到困难,可以在另一个选项卡或文本编辑器中打开 superheroes.json 文件,并在查看 JavaScript 时引用它,这会有所帮助。你还应该参阅我们的 JavaScript 对象基础知识 文章,了解有关点和括号表示法的更多信息。

¥Note: If you are having trouble following the dot/bracket notation we are using to access the JavaScript object, it can help to have the superheroes.json file open in another tab or your text editor, and refer to it as you look at our JavaScript. You should also refer back to our JavaScript object basics article for more information on dot and bracket notation.

调用顶层函数

¥Calling the top-level function

最后,我们需要调用顶层 populate() 函数:

¥Finally, we need to call our top-level populate() function:

js
populate();

对象和文本之间的转换

¥Converting between objects and text

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

¥The above example was simple in terms of accessing the JavaScript object, because we converted the network response directly into a JavaScript object using response.json().

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

¥But sometimes we aren't so lucky — sometimes we receive a raw JSON string, and we need to convert it to an object ourselves. And when we want to send a JavaScript object across the network, we need to convert it to JSON (a string) before sending it. Luckily, these two problems are so common in web development that a built-in JSON object is available in browsers, which contains the following two methods:

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

你可以在我们的 heroes-finished-json-parse.html 示例中看到第一个示例(参见 源代码) - 它的作用与我们之前构建的示例完全相同,除了:

¥You can see the first one in action in our heroes-finished-json-parse.html example (see the source code) — this does exactly the same thing as the example we built up earlier, except that:

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

关键代码片段在这里:

¥The key snippet of code is here:

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 控制台中以查看其实际效果:

¥As you might guess, stringify() works the opposite way. Try entering the following lines into your browser's JavaScript console one by one to see it in action:

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

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

¥Here we're creating a JavaScript object, then checking what it contains, then converting it to a JSON string using stringify() — saving the return value in a new variable — then checking it again.

测试你的技能!

¥Test your skills!

你已读完本文,但你还记得最重要的信息吗?在继续之前,你可以找到一些进一步的测试来验证你是否已保留此信息 - 请参阅 测试你的技能:JSON

¥You've reached the end of this article, but can you remember the most important information? You can find some further tests to verify that you've retained this information before you move on — see Test your skills: JSON.

概括

¥Summary

在本文中,我们为你提供了在程序中使用 JSON 的简单指南,包括如何创建和解析 JSON,以及如何访问锁定在其中的数据。在下一篇文章中,我们将开始研究面向对象的 JavaScript。

¥In this article, we've given you a simple guide to using JSON in your programs, including how to create and parse JSON, and how to access data locked inside it. In the next article, we'll begin looking at object-oriented JavaScript.

也可以看看