JavaScript对象表示法(JSON)是用于将结构化数据表示为JavaScript对象的标准格式,通常用于在网站上表示和传输数据 (i.e. 从服务器向客户端发送一些数据,因此可以将其显示在网页上). 您会经常遇到它,所以在本文中,我们向您提供使用JavaScript处理JSON的所有工作,包括访问JSON对象中的数据项并编写自己的JSON。
前提: | 计算机基础知识,HTML 和 CSS 基础 (see First steps and Building blocks) 和 JS 面向对象基础(see Introduction to objects)。 |
---|---|
目标: | 理解 JSON 的数据储存工作原理,创建你的 JSON 对象。 |
不,说真的,什么是 JSON?
JSON 是一种按照JavaScript对象语法的数据格式,这是 Douglas Crockford 推广的。虽然它是基于 Javascript 语法,但它独立于javaScript,这也是为什么许多程序环境能够读取(解读)和生成 JSON。
JSON可以作为一个对象或者字符串存在,前者用于解读 JSON 中的数据,后者用于通过网络传输 JSON 数据。 这不是一个大事件——JavaScript 提供一个全局的 可访问的 JSON 对象来对这两种数据进行转换。
一个 JSON 对象可以被储存在它自己的文件中,这基本上就是一个文本文件,扩展名为 .json, 还有 MIME type 用于 application/json
.
JSON 结构
我们已经可以推测出 JSON 对象就是基于 Javascript 对象,而且这几乎是正确的。你可以把 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 对象为例,我们使用 . 或 [] 访问对象内的数据(关于. 和 []概念,见
对象基础 )。例如:
superHeroes.hometown superHeroes["active"]
为了访问对象中的对象,你只需简单地链式访问(通过属性名和数组索引)。例如,访问 superHeroes 对象中的 members 数组对象的第二个元素的 powers 数组对象的第三个元素,你可以这样做:
superHeroes["members"][1]["powers"][2]
- 首先我们有变量名 superHeroes,储存对象 。
- 在对象中我们想访问 members 属性,所以我们使用
["members"]
. members 包含有对象数组,我们想要访问第二个元素,
所以我们使用[1]
.- 在对象内,我们想访问 powers 属性,所以我们使用
["powers"]
. - powers 属性是一个包含英雄技能的数组。我们想要第三个,所以我们使用
[2]
.
注:我们已经在 JSONText.html 实例中让JSON 对象进入变量中使其可访问(see the source code)。尝试加载它并且在您的浏览器上访问对象数据。
JSON 数组
前面我们已经说过,”我们已经可以推测出 JSON 对象就是基于 Javascript 对象,而且这几乎是正确的“——我们说几乎正确的原因是数组对象也是一种合法的 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 很少出错,只要生成程序正常工作)。你可以通过像 JSONLint 的应用程序来检验 JSON。
- JSON 可以将任何标准合法的 JSON 数据格式化保存,不只是数组和对象。比如,一个单一的字符串或者数字可以是合法的 JSON 对象。虽然不是特别有用处……
- 不像 JavaScript 标识符可以用作属性,在 JSON 中,只有字符串才能用作属性。
积极学习 : 一个JSON 示例
好了,让我们通过运行这个示例来展示我们如何利用JSON数据。
开始吧
首先,拷贝我们的 heroes.html 和 style.css 文件。后者包含了用于页面的简单的 CSS ,前者包含了简单的 HTML body。
<header> </header> <section> </section>
添加 <script>元素来包含我们的 JavaScript 代码。当前它只有两行,获得了<header> 和 <section> 的引用,保存在变量中。
var header = document.querySelector('header'); var section = document.querySelector('section');
我们已经把 JSON 数据放在了GitHub 上面 https://mdn.github.io/learning-area/javascript/oojs/json/superheroes.json。
我们准备把它加载到我们的页面中,然后使用漂亮的 DOM 操作来展示它,就像这样:
加载我们的JSON
为了载入 JSON 到页面中,我们将使用 一个名为 XMLHttpRequest 的API(常称为XHR)。这是一个非常有用的 JavaScript 对象,使我们能够通过代码来向服务器请求资源文件(如:图片,文本,JSON,甚至HTML片段),意味着我们可以更新小段内容而不用重新加载整个页面。这将有更多响应页面,听起来让人兴奋,但是这部分超出我们本部分的文章,所以就不多详述了。
- 首先,我们将保存一个即将访问的 URL 作为变量。在你的 JavaScript 代码的底部添加下面的代码:
var requestURL = 'https://mdn.github.io/learning-area/javascript/oojs/json/superheroes.json';
- 为了创建一个Http请求,我们需要创建一个Http请求对象,通过 new 构造函数的形式。在你最下面的代码中写入:
var request = new XMLHttpRequest();
- 现在我们需要使用
open()
函数打开一个新的请求,添加如下代码:request.open('GET', requestURL);
这个函数至少含有两个参数,其它的是可选参数。对于示例我们只需要两个强制参数
- HTTP 方法,网络连接时使用。这个示例中
GET
就可以了,因为我们只要获得简单的数据。 - URL,用于指向请求的地址。我们使用之前保存的变量。
- HTTP 方法,网络连接时使用。这个示例中
- 接下来,添加,两行代码,我们设定
responseType
为 JSON,所以服务器将知道我们想要返回一个 JSON 对象,然后发送请求 :request.responseType = 'json'; request.send();
- 最后一点内容涉及相应来自服务器的返回数据,然后处理它,添加如下代码在你先前的代码下方:
request.onload = function() { var superHeroes = request.response; populateHeader(superHeroes); showHeroes(superHeroes); }
这儿我们保存了相应我们请求的数据(访问 response
属性) 于变量 superHeroes ;这个变量现在含有 JSON!我们现在把 superHeroes 传给两个函数,第一个函数将会用正确的数据填充<header>,同时第二个函数将创建一个信息卡片,然后把它插入<section>中。
我们把代码包在事件处理函数中,当请求对象 load 事件触发时执行代码(见onload
),这是因为请求对象 load 事件只有在请求成功时触发;这种方式可以保证事件触发时 request.response
是绝对可以访问的。
定位 header
现在我们已经获得我们的JSON数据,让我们利用它来写两个我们使用的函数。首先,添加下面的代码于之前的代码下方:
function populateHeader(jsonObj) { var myH1 = document.createElement('h1'); myH1.textContent = jsonObj['squadName']; header.appendChild(myH1); var myPara = document.createElement('p'); myPara.textContent = 'Hometown: ' + jsonObj['homeTown'] + ' // Formed: ' + jsonObj['formed']; header.appendChild(myPara); }
我们称参数为 jsonObj
,那也是为什么我们要在其中调用 JSON 对象。这儿我们首先使用 createElement()
创建了一个 <h1>
节点,将它的 textContent
设为 JSON 对象的 squadName
属性,然后通过 appendChild()
把它加入 <header>
中。然后我们对段落做了相同的一件事情:创建,设置内容,追加到 <header>
。唯一的不同在于它的内容设为一个与 JSON 内属性 homeTown
和 formed 相关联的字符串。
创建英雄信息卡片
接下来,添加如下的函数到脚本代码底部,这个函数创建和展示了 superhero cards:
function showHeroes(jsonObj) { var heroes = jsonObj['members']; for(i = 0; i < heroes.length; i++) { var myArticle = document.createElement('article'); var myH2 = document.createElement('h2'); var myPara1 = document.createElement('p'); var myPara2 = document.createElement('p'); var myPara3 = document.createElement('p'); var myList = document.createElement('ul'); myH2.textContent = heroes[i].name; myPara1.textContent = 'Secret identity: ' + heroes[i].secretIdentity; myPara2.textContent = 'Age: ' + heroes[i].age; myPara3.textContent = 'Superpowers:'; var superPowers = heroes[i].powers; for(j = 0; j < superPowers.length; j++) { var listItem = document.createElement('li'); listItem.textContent = superPowers[j]; myList.appendChild(listItem); } myArticle.appendChild(myH2); myArticle.appendChild(myPara1); myArticle.appendChild(myPara2); myArticle.appendChild(myPara3); myArticle.appendChild(myList); section.appendChild(myArticle); } }
首先,我们保存了 JSON 的 members
属性作为一个变量。这个数组含有多个带有英雄信息的对象。
接下来,我们使用一个循环来,遍历每个元素。对于每一个元素,我们:
- 创建几个元素: 一个
<article>
,一个<h2>
, 三个<p>
s, 和一个<ul>。
- 设置 <h2> 为当前英雄的 name。
- 使用他们的
secretIdentity
,age
, "Superpowers:" 介绍信息列表 填充三个段落来。 - 保存
powers
属性于另一个变量superPowers
,包含英雄的superpowers列表。 - 使用另一个循环来遍历当前的英雄的 superpowers ,对于每一个元素我们创建
<li>
元素,把superpower 放进去,然后使用appendChild()
把listItem
放入<ul>
元素中。 - 最后一件事情是追加
<h2>,<p>,还有
<ul>进入
<article>
(myArticle
)。然后将<article>
追加到<section>。追加的顺序很重要,因为他们将被展示在 HTML 中。
Note: 如有疑难,试试引用我们的 heroes-finished.html 代码(也可见 running live )。
Note: 如果你对访问 JSON对象的 点/括号标记 有困扰。获得文件 superheroes.json 并在你的编辑器中打开参考我们的 JS 代码将会有帮助。您还应该参考我们的 JavaScript object basics文章,了解关于点和括号符号的更多信息。
对象和文本间的转换
上述示例就访问 JSON 而言是简单的,因为我们设置了 XHR 来访问 JSON 格式数据:
request.responseType = 'json';
但是有时候我们没有那么幸运,我们接收到一些 字符串作为 JSON 数据,然后我们想要将它转换为对象。当我们想要发送 JSON 数据作为信息,我们将需要转换它为字符串,我们经常需要正确的转换数据,幸运的是,这两个问题在web环境中是那么普遍以至于浏览器拥有一个内建的 JSON,包含以下两个方法。
parse()
: 接收一个字符串最为参数,返回一个对应的对象。stringify()
: 接收一个JSON对象作为参数,返回一个对应的字符串。
你可以看看我们 heroes-finished-json-parse.html 示例的第一个操作 (见 source code) ,除了返回的是 text,这做了一件与我们之前一摸一样的事情,然后使用 parse()
来将他转换成为 JSON 对象。关键片段如下:
request.open('GET', requestURL); request.responseType = 'text'; // now we're getting a string! request.send(); request.onload = function() { var superHeroesText = request.response; // get the string from the response var superHeroes = JSON.parse(superHeroesText); // convert it to an object populateHeader(superHeroes); showHeroes(superHeroes); }
正如你所想, stringify()
做相反的事情. 尝试将下面的代码输入你的浏览器 JS 控制台来看看会发生什么:
var myJSON = { "name" : "Chris", "age" : "38" }; myJSON var myString = JSON.stringify(myJSON); myString
这儿我们创建了一个JSON 对象,然后检查了它包含了什么,然后用stringify()
将它转换成字符串,最后保存返回值作为变量。然后再一次检查。
总结
在这个文章中,我们给了你一个简单的示例来在自己的程序中使用 JSON,包括创建和处理 JSON,还有如何访问 JSON 内的数据。在下一篇文章中我们将开始关注JS中的面向对象内容。