关注前端小讴,阅读更多原创技术文章
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()的第二个参数(还原函数)进行字符串解析
JSON (JavaScript Object Notation) is a universal data format with syntax similar to JavaScript. It supports simple values (strings, numbers, booleans, null), objects (ordered key/value pairs), and arrays (ordered lists). The JSON.stringify()
method serializes JavaScriptJavaScript objects into JSON strings, while JSON.parse()
converts converts JSON strings back into JavaScript objects. Custom serialization can be achieved using filters, indentation options, and the toJSON()
method. Parsing can also be customized using reduction functions.
不错