关注前端小讴,阅读更多原创技术文章
JSON
- JSON 是 JS 对象简谱,是一种通用的数据格式
- 和 JS 有相同的语法,但不属于 JS,很多语言都能解析和序列化 JSON
语法
JSON 支持 3 种类型的值
- 简单值:字符串、数值、布尔值、null,undedined 不可以
- 对象:复杂数据类型,有序键/值对,每个值可以是简单值/复杂类型
- 数组:复杂数据类型,通过数值索引访问的值的有序列表,每个值可以是任意类型
简单值
- 可以是一个数值
5
- 可以是一个字符串,与 JS 字符串的区别在于,必须使用双引号(单引号会导致语法错误)
"1"
- 可以是布尔值、null,但不能是 undefined
对象
与 JS 字面量的区别在于,属性名必须使用双引号
- 还有 2 处不同在于,没有变量声明、末尾无分号
// js字面量
let person = {
name: "Nicholas",
age: "29",
};
// json对象
{
"name": "Nicholas",
"age": "29"
}
- 属性的值也可以是复杂数据类型
{
"name": "Nicholas",
"age": "29",
"school": {
"name": "m college",
"lacation": "a street"
}
}
数组
- 与 JS 数组的区别在于,没有变量声明、末尾无分号
// js数组
let values = [25, "hi", true];
// json数组
[25, "hi", true]
- 数组和对象可以组合使用,以表示更复杂的数据结构
[
{
"name": "Nicholas",
"age": "29",
"school": {
"name": "m college",
"lacation": "a street"
}
},
{
"name": "Matt",
"age": "27",
"school": {
"name": "n college",
"lacation": "b street"
}
}
]
解析与序列化
JSON 对象
JSON 对象有 2 个方法
- stringify()将 js 序列化为 JSON 字符串
let book = { title: "Professional", authors: ["Nicholas", "Matt"], edition: 4, year: 2017, }; let jsonText = JSON.stringify(book); console.log(jsonText); // {"title":"Professional","authors":["Nicholas","Matt"],"edition":4,"year":2017}
- parse()将 JSON 字符串解析为原生 js 值
let bookCopy = JSON.parse(jsonText); let bookCopy = JSON.parse(jsonText); console.log(bookCopy); /* { title: 'Professional', authors: [ 'Nicholas', 'Matt' ], edition: 4, year: 2017 } */
- 可一并使用JSON.stringify()和JSON.parse()进行对象深拷贝
let bookCopy2 = JSON.parse(JSON.stringify(book)); // 深拷贝 console.log(bookCopy2);
- 序列化 JS 对象时,所有函数、原型成员、值为 undefined的属性会在结果中省略
let book2 = {
title: "Professional",
authors: ["Nicholas", "Matt"],
edition: () => {}, // 序列化时会被省略
year: undefined, // 序列化时会被省略
};
let jsonText2 = JSON.stringify(book2);
console.log(jsonText2); // {"title":"Professional","authors":["Nicholas","Matt"]}
let bookCopy3 = JSON.parse(jsonText2);
console.log(bookCopy3);
/*
{
title: 'Professional',
authors: [ 'Nicholas', 'Matt' ]
}
*/
序列化选项
JSON.stringify()接受 2 个参数:过滤器和用于缩进结果 JSON 字符串的选项
- 第 2 个参数是数组,返回只包含该数组中列出的对象属性
let jsonText3 = JSON.stringify(book, ["title", "edition"]); // 只返回包含title和edition属性 console.log(jsonText3); // {"title":"Professional","edition":4}
- 第 2 个参数是函数,函数接受 2 个参数 key 和 value,根据 key 决定要对应属性执行的操作
let jsonText4 = JSON.stringify(book, (key, value) => { switch (key) { case "authors": return value.join(","); // 将数值转换为字符串 case "year": return 5000; // 返回5000 case "edition": return undefined; // 忽略该属性 default: return value; // 必须设置默认返回值 } }); console.log(jsonText4); // {"title":"Professional","authors":"Nicholas,Matt","year":5000}
- 函数过滤器会应用到要序列化对象所包含的所有对象
let book3 = { title: "Professional", authors: ["Nicholas", "Matt"], edition: 4, year: 2017, book3: { title: "Professional2", authors: ["Nicholas", "Matt"], edition: 4, year: 2017, }, // 对book3做序列化时,内层的book3对象同样受影响 }; let jsonText5 = JSON.stringify(book3, (key, value) => { switch (key) { case "authors": return value.join(","); case "year": return 5000; case "edition": return undefined; default: return value; } }); console.log(jsonText5); // {"title":"Professional","authors":"Nicholas,Matt","year":5000,"book3":{"title":"Professional2","authors":"Nicholas,Matt","year":5000}}
JSON.stringify()的第 3 个参数控制缩进和空格,且所有有效缩进都插入换行符
- 第 3 个参数是数值,表示每级缩进的空格数(最大为 10,大于 10 自动为 10)
let jsonText6 = JSON.stringify(book, null, 4); // 每级缩进4个空格 console.log(jsonText6); /* { "title": "Professional", "authors": [ "Nicholas", "Matt" ], "edition": 4, "year": 2017 } */
- 第 3 个参数是字符串,表示使用该字符串缩进
let jsonText7 = JSON.stringify(book, null, "-"); // 使用'-'缩进 console.log(jsonText7); /* { -"title": "Professional", -"authors": [ --"Nicholas", --"Matt" -], -"edition": 4, -"year": 2017 } */
可在要序列化对象中添加 toJSON()方法,使用 JSON.stringify()方法序列化时则自动适当的 JSON 表示
let book4 = { title: "Professional", authors: ["Nicholas", "Matt"], edition: 4, year: 2017, toJSON: function () { return this.title; // 执行toJSON(),返回值直接return }, }; let jsonText8 = JSON.stringify(book4); console.log(jsonText8); // "Professional"
- 箭头函数不能定义 toJSON() 方法,因为其作用域是全局作用域
- toJSON() 可与过滤函数一并使用:① 调用 toJSON()获取实际返回值(如没有则使用默认的序列化) ② 将该值传入过滤函数
let num = { toJSON: function () { return 123; }, }; let book5 = { title: "Professional", authors: ["Nicholas", "Matt"], edition: 4, year: 2017, num, }; let jsonText9 = JSON.stringify(book5, ["title", "edition", "num"], 4); // JSON.stringify()时默认调用num的toJSON()方法 console.log(jsonText9); /* { "title": "Professional", "edition": 4, "num": 123 } */
解析选项
- JSON.parse() 接受一个还原函数,函数接受 2 个参数 key 和 value,根据 key 决定要对应属性执行的操作
let book6 = {
title: "Professional",
authors: ["Nicholas", "Matt"],
edition: 4,
year: 2017,
num,
};
let jsonText10 = JSON.stringify(book6);
let bookCopy4 = JSON.parse(jsonText10, (key, value) =>
key === "year" ? value + 1 : value
);
console.log(bookCopy4);
/*
{
title: 'Professional',
authors: [ 'Nicholas', 'Matt' ],
edition: 4,
year: 2018,
num: 123
}
*/
- 与 JSON.stringify()第 2 个参数为函数时相似,返回值为undefined的建将被忽略
let bookCopy5 = JSON.parse(
jsonText10,
(key, value) => (key === "year" ? undefined : value) // 返回值为undefined的建将被忽略
);
console.log(bookCopy5);
/*
{
title: 'Professional',
authors: [ 'Nicholas', 'Matt' ],
edition: 4,
num: 123
}
*/
总结 & 问点
- JSON 支持哪些类型的值?各种类型相比 JS 分别有哪些不同的语法?
- 如何利用 JSON 序列化进行深拷贝?哪些情况下序列化后对象的属性会被省略?
- JSON.stringify()的第二个参数为数组或函数时,分别对结果进行了怎样的过滤?
- JSON.stringify()的第三个参数为数值或字符串时,分别对结果进行了怎样的缩进?
- 写一段代码,使用 toJSON()结合过滤函数对 JSON 进行序列化
- 写一段代码,利用 JSON.parse()的第二个参数(还原函数)进行字符串解析
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。