使用 JSON
JavaScript 对象表示法 (JSON) 是一种基于 JavaScript 对象语法表示结构化数据的标准文本格式。它通常用于在 Web 应用程序中传输数据(例如,将一些数据从服务器发送到客户端,以便在网页上显示,反之亦然)。您会经常遇到它,因此在本文中,我们为您提供了使用 JavaScript 处理 JSON 所需的所有内容,包括解析 JSON 以便您可以访问其中的数据,以及创建 JSON。
不,真的,什么是 JSON?
JSON 是一种基于文本的数据格式,遵循 JavaScript 对象语法,由 道格拉斯·克罗克福德 推广。尽管它与 JavaScript 对象字面量语法非常相似,但它可以独立于 JavaScript 使用,并且许多编程环境都具有读取(解析)和生成 JSON 的能力。
JSON 存在于字符串中——当您想要跨网络传输数据时非常有用。当您想要访问数据时,需要将其转换为本机 JavaScript 对象。这不是什么大问题——JavaScript 提供了一个全局 JSON 对象,其中包含用于在两者之间转换的方法。
注意:将字符串转换为本机对象称为反序列化,而将本机对象转换为字符串以便能够跨网络传输则称为序列化。
JSON 字符串可以存储在它自己的文件中,该文件基本上只是一个扩展名为 .json
且 MIME 类型 为 application/json
的文本文件。
JSON 结构
如上所述,JSON 是一个字符串,其格式非常类似于 JavaScript 对象字面量格式。您可以在 JSON 中包含与标准 JavaScript 对象中相同的基本数据类型——字符串、数字、数组、布尔值和其他对象字面量。这允许您构建数据层次结构,如下所示
{
"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 对象基础知识 文章中看到的相同的点/括号表示法来访问其中的数据。例如
superHeroes.homeTown;
superHeroes["active"];
要访问层次结构中更深层的数据,您必须将所需的属性名称和数组索引链接在一起。例如,要访问成员列表中第二个英雄的第三个超能力,您可以执行以下操作
superHeroes["members"][1]["powers"][2];
- 首先,我们有变量名——
superHeroes
。 - 在其中,我们想访问
members
属性,所以我们使用["members"]
。 members
包含一个由对象填充的数组。我们想访问数组中的第二个对象,所以我们使用[1]
。- 在此对象中,我们想访问
powers
属性,所以我们使用["powers"]
。 powers
属性中包含一个数组,其中包含所选英雄的超能力。我们想要第三个,所以我们使用[2]
。
注意:我们在 JSONTest.html 示例中(参见 源代码)的变量中提供了上面看到的 JSON。尝试加载它,然后通过浏览器的 JavaScript 控制台访问变量中的数据。
数组作为 JSON
上面我们提到 JSON 文本基本上看起来像字符串中的 JavaScript 对象。我们还可以将数组转换为 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.html 和 style.css 文件的本地副本。后者包含一些简单的 CSS 来设置页面的样式,而前者包含一些非常简单的正文 HTML,以及一个 <script>
元素,用于包含我们将在本练习中编写的 JavaScript 代码
<header>
...
</header>
<section>
...
</section>
<script>
...
</script>
我们已在 GitHub 上提供了我们的 JSON 数据,网址为 https://mdn.github.io/learning-area/javascript/oojs/json/superheroes.json。
我们将 JSON 加载到我们的脚本中,并使用一些巧妙的 DOM 操作来显示它,如下所示
顶级函数
顶级函数如下所示
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 对象,让我们通过编写上面提到的两个函数来使用它。首先,在之前的代码下方添加以下函数定义
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()
将其附加到标题。然后,我们对段落执行非常类似的操作:创建它,设置其文本内容并将其附加到标题。唯一的区别是它的文本设置为包含对象的 homeTown
和 formed
属性的 模板字面量。
创建英雄信息卡
接下来,在代码底部添加以下函数,该函数创建并显示超级英雄卡片
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 循环 遍历数组中的每个对象。对于每个对象,我们
- 创建几个新元素:一个
<article>
、一个<h2>
、三个<p>
和一个<ul>
。 - 将
<h2>
设置为包含当前英雄的name
。 - 使用他们的
secretIdentity
、age
和一行“超能力:”来填充三个段落,以介绍列表中的信息。 - 将
powers
属性存储在另一个名为superPowers
的新常量中——它包含一个列出当前英雄超能力的数组。 - 使用另一个
for...of
循环遍历当前英雄的超能力——对于每个超能力,我们创建一个<li>
元素,将超能力放入其中,然后使用appendChild()
将listItem
放入<ul>
元素(myList
)中。 - 我们做的最后一件事是将
<h2>
、<p>
和<ul>
附加到<article>
(myArticle
)中,然后将<article>
附加到<section>
中。附加事物的顺序很重要,因为这是它们在 HTML 中显示的顺序。
注意:如果您在使示例工作时遇到问题,请尝试参考我们的 heroes-finished.html 源代码(也可以查看 在线运行 的代码)。
注意:如果您在理解我们用于访问 JavaScript 对象的点/括号表示法时遇到困难,可以尝试在另一个标签页或文本编辑器中打开superheroes.json文件,并在查看 JavaScript 代码时参考它。您还可以参考我们的JavaScript 对象基础文章,以获取有关点和括号表示法的更多信息。
调用顶级函数
最后,我们需要调用我们的顶级populate()
函数
populate();
在对象和文本之间转换
以上示例在访问 JavaScript 对象方面很简单,因为我们使用response.json()
将网络响应直接转换为 JavaScript 对象。
但有时我们没那么幸运——有时我们会收到原始的 JSON 字符串,我们需要自己将其转换为对象。当我们想要通过网络发送 JavaScript 对象时,需要在发送之前将其转换为 JSON(字符串)。幸运的是,这两个问题在 Web 开发中非常常见,浏览器中提供了一个内置的JSON对象,其中包含以下两种方法
parse()
:接受 JSON 字符串作为参数,并返回相应的 JavaScript 对象。stringify()
:接受对象作为参数,并返回等效的 JSON 字符串。
您可以在我们的heroes-finished-json-parse.html示例中看到第一个方法的应用(参见源代码)——它与我们之前构建的示例完全相同,只是
- 我们通过调用响应的
text()
方法,以文本而不是 JSON 的形式检索响应 - 然后我们使用
parse()
将文本转换为 JavaScript 对象。
关键代码片段如下所示
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 控制台中,以查看其运行效果
let myObj = { name: "Chris", age: 38 };
myObj;
let myString = JSON.stringify(myObj);
myString;
这里我们创建了一个 JavaScript 对象,然后检查其内容,然后使用stringify()
将其转换为 JSON 字符串——将返回值保存在一个新变量中——然后再次检查它。
测试你的技能!
您已经阅读完了本文,但您还记得最重要的信息吗?在继续学习之前,您可以进行一些额外的测试来验证您是否掌握了这些信息——请参阅测试您的技能:JSON。
总结
在本文中,我们为您提供了使用 JSON 进行编程的简单指南,包括如何创建和解析 JSON,以及如何访问其中包含的数据。在下一篇文章中,我们将开始学习面向对象的 JavaScript。