JSON

262 阅读4分钟

学习了coderwhy的JavaScript高级语法视频课的笔记

如有错误或者不合适的地方,敬请见谅,欢迎指出和拓展,谢谢各位了

1. JSON的由来

  • 在目前的开发中,JSON是一种非常重要的数据格式,它并不是编程语言,而是一种可以在服务器和客户端之间传输的数据格式。
  • JSON的全称是JavaScript Object Notation(JavaScript对象符号):
    • JSON是由Douglas Crockford构想和设计的一种轻量级资料交换格式,算是JavaScript的一个子集;
    • 虽然JSON被提出来的时候是主要应用JavaScript中,但是目前已经独立于编程语言,可以在各个编程语言中使用;
    • 很多编程语言都实现了将JSON转成对应模型的方式。
  • 其他的传输格式:
    • XML:在早期的网络传输中主要是使用XML来进行数据交换的,但是这种格式在解析、传输等各方面都弱于JSON,所以目前已经很少在被使用了;
    • Protobuf:另外一个在网络传输中目前已经越来越多使用的传输格式是protobuf,但是直到2021年的3.x版本才支持JavaScript,所以目前在前端使用的较少。
  • 目前JSON被使用的场景也越来越多:
    • 网络数据的传输JSON数据;
    • 项目的某些配置文件;
    • 非关系型数据库(NoSQL)将json作为存储格式。

2. JSON的基本语法

  1. JSON的顶层支持三种类型的值:
  • 简单值:数字(Number)、字符串(String,不支持单引号)、布尔类型(Boolean)、null类型;
  • 对象值:由key、value组成,key是字符串类型,并且必须添加双引号,值可以是简单值、对象值、数组值;
    • 数组值:数组的值可以是简单值、对象值、数组值。 注意:json文件不能有注释。
  1. JSON序列化
  • 某些情况下我们希望将JavaScript中的复杂类型转化成JSON格式的字符串,这样方便对其进行处理:
    • 比如我们希望将一个对象保存到localStorage中;
    • 但是如果我们直接存放一个对象,这个对象会被转化成 [object Object] 格式的字符串,并不是我们想要的结果。
  • 在ES5中引用了JSON全局对象,该对象有两个常用的方法:
  • stringify方法:将JavaScript类型转成对应的JSON字符串;
  • parse方法:解析JSON字符串,转回对应的JavaScript类型。
const obj = {
  name: 'aaa',
  info: {
    name: 'bbb'
  }
}

const objString = JSON.stringify(obj)

console.log(typeof objString) //string
console.log(objString) //{ name: 'aaa', info: { name: 'bbb' } }

console.log(typeof JSON.parse(objString)) //object
console.log(JSON.parse(objString)) //{ name: 'aaa', info: { name: 'bbb' } }
  1. 序列化方法 stringify 的细节
  • stringify的第二个参数replacer
    • JSON.stringify() 方法将一个 JavaScript 对象或值转换为 JSON 字符串:
      • 如果指定了一个 replacer 函数,则可以选择性地替换值
      • 如果指定的 replacer 是数组,则可选择性地仅包含数组指定的属性
const obj = {
  name: 'aaa',
  info: {
    name: 'bbb'
  }
}

// 1、stringify的第二个参数replacer
// 1.1函数
const objString = JSON.stringify(obj, (key, value) => {
  if (key === 'info') {
    return 'ccc'
  }
  return value
})

console.log(objString) //{"name":"aaa","info":"ccc"}

// 1.2数组:设定哪些是需要转换
// info对象中的属性也要符合数组里的值,才能选择性地仅包含数组指定的属性
const objString2 = JSON.stringify(obj, ['info'])
console.log(objString2) //{"info":{}}

const objString3 = JSON.stringify(obj, ['name', 'info'])
console.log(objString3) //{"name":"aaa","info":{"name":"bbb"}}
  • stringify的第三个参数space
const obj = {
  name: 'aaa',
  info: {
    name: 'bbb'
  }
}

// stringify第三参数 space,格式缩进的替换字符,可以是空格等
const jsonString = JSON.stringify(obj, null, '---')
console.log(jsonString)
/* {
---"name": "aaa",
---"info": {
------"name": "bbb"
---}
} */
  • 如果对象本身包含toJSON方法,那么会直接使用toJSON方法的结果
const obj = {
  name: 'aaa',
  info: {
    name: 'bbb'
  },
  toJSON: function () {
    return '直接使用toJSON方法的结果'
  }
}

const jsonString = JSON.stringify(obj)
console.log(jsonString) //"直接使用toJSON方法的结果"
  1. 序列化方法 parse 的细节
  • JSON.parse() 方法用来解析JSON字符串,构造由字符串描述的JavaScript值或对象
    • 提供可选的 reviver 函数用以在返回之前对所得到的对象执行变换(操作)。
const jsonString = '{"name":"aaa","info":{"name":"bbb"}}'

const obj = JSON.parse(jsonString, (key, value) => {
  if (key === 'info') {
    return 'ccc'
  }
  return value
})

console.log(obj) //{ name: 'aaa', info: 'ccc' }
  1. 使用JSON序列化深拷贝
const obj = {
  name: 'aaa',
  info: {
    name: 'bbb'
  },
  foo: function () {
    console.log('foo function')
  }
}

// 将obj对象的内容放到aaa变量中
// 1.引用赋值
const aaa = obj
obj.name = 'ccc'
console.log(aaa.name) //ccc

// 2.浅拷贝
const aaa2 = { ...obj }
obj.name = 'ddd'
console.log(aaa2.name) //打印出 1.引用赋值 中修改的值:ccc

//这里没有实现深拷贝,所以会变
obj.info.name = 'xxx'
console.log(aaa2.info.name) //xxx

// 3.stringify和parse来实现深拷贝
// 注意:这种方法它对函数是无能为力的
const jsonString = JSON.stringify(obj)
console.log(jsonString) //{"name":"ddd","info":{"name":"xxx"}}
const aaa3 = JSON.parse(jsonString)
console.log(aaa3) //{ name: 'ddd', info: { name: 'xxx' } }

//这里实现了深拷贝,所以不会变
obj.info.name = 'yyy'
console.log(aaa3.info.name) //打印出 2.浅拷贝 中修改的值:xxx
  • 注意:这种方法它对函数是无能为力的
    • 这是因为stringify并不会对函数进行处理
  • 上面的浅拷贝也就是obj里面的值复制一份给了另一个对象,所以aaa2和obj的地址指向不是同一个对象,但是obj中的info和aaa2中的info指向还是同一个对象。深拷贝就是使obj中的info和aaa2中的info指向不是同一个对象。