关注前端小讴,阅读更多原创技术文章

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()的第二个参数(还原函数)进行字符串解析

小讴
217 声望16 粉丝