JSON 详解

2023-12-30 15:36:20

json 相信大家一定耳熟能详,但是其实 json 在 JavaScript 中很多细节,本文就来详细讲解 json 在 JavaScript 中那些隐藏的秘密

JSON 的由来

  1. JSON 是一种数据格式,而不是编程语言,目前广泛用于客户端和服务器之间传输的数据格式
  2. JSON 全称 JavaScript Object Notation(JavaScript 对象符号)
    1. JSON 是由Douglas Crockford构想和设计的一种轻量级资料交换格式,算是 JavaScript 的一个子集
    2. 虽然 JSON 被提出来的时候是主要应用 JavaScript 中,但是目前已经独立于编程语言,可以在各个编程语言中被广泛的使用

JSON 的基本语法

  1. JSON 支持三种类型的值:
    1. 简单值:数字、字符串(不支持单引号)、布尔类型、null 类型
    2. 对象值:由key、value组成,key是字符串类型,并且必须添加双引号,值可以是简单值、对象值、数组值
    3. 数组值:数组的值可以是简单值、对象值、数组值
  2. tips:JSON 里面不能添加注释
  3. 具体的写法大家应该都知道,这里就不写示例代码了

JSON 的序列化

相信这个大家都知道,在 JavaScript 中的 JSON 对象上存在两个方法 stringify 和 parse,就可以实现序列化

序列化是将数据结构或对象转换为符合 JSON 格式的字符串的过程

简单使用

const obj = {
	name: '张三',
	age: 18,
	frienfs: [
		{ name: '李四', age: 20 },
		{ name: '王五', age: 22 }
	],
	hobbies: ['篮球', '足球', '乒乓球']
}

// 使用 stringify 方法转为 JSON 格式的字符串
const str = JSON.stringify(obj)

// 使用 parse 方法将一个 JSON 格式的字符串转为一个对象
const newObj = JSON.parse(str)

stringify 方法之 replacer

  1. stringify 方法的第一个参数大家都知道,那第二个参数(replacer)了解吗?

  2. replacer 是一个可选参数,replacer 的作用是指定需要想转换的值,是一个数组,或 null(全部转换) ,如下:

    const obj = {
    	name: '张三',
    	age: 18,
    	friends: [
    		{ name: '李四', age: 20 },
    		{ name: '王五', age: 22 }
    	],
    	hobbies: ['篮球', '足球', '乒乓球']
    }
    
    // 正常转换
    const str1 = JSON.stringify(obj)
    console.log('str1: ', str1)
    
    // 排除 friends 和 hobbies
    const str2 = JSON.stringify(obj, ['name', 'age'])
    console.log('str2: ', str2)
    
  3. 结果如图:

    在这里插入图片描述

  4. 此时就可以发现,只转换了我们需要的部分,当我们存在这样的需求的时候,使用这个参数,是非常方便的

  5. tips:所有以 symbol 为属性键的属性都会被完全忽略掉,即便 replacer 参数中强制指定包含了它们

stringify 方法之 replacer 参数传入回调函数

  1. 上述例子中可以一定程度上实现一些额外的需求,但是针对高度自定义的需求还是有点无能为力,那么此时我们可以给其参数改为传入一个回调函数

  2. 传入一个回调函数时,会接收两个参数,key 和 value,而每一次进行序列转换的时候就会执行一次,如下:

    const obj = {
    	name: '张三',
    	age: 18,
    	friends: [
    		{ name: '李四', age: 20 },
    		{ name: '王五', age: 22 }
    	],
    	hobbies: ['篮球', '足球', '乒乓球']
    }
    
    const str = JSON.stringify(obj, (key, value) => {
    	console.log(key, value)
    	return value
    })
    
    console.log(str)
    
  3. 执行结果如图:
    在这里插入图片描述

  4. 比如我们需要给 name 的值添加一个 @ 符号,并年龄 +1,如下:

    const obj = {
    	name: '张三',
    	age: 18,
    	friends: [
    		{ name: '李四', age: 20 },
    		{ name: '王五', age: 22 }
    	],
    	hobbies: ['篮球', '足球', '乒乓球']
    }
    
    const str = JSON.stringify(obj, (key, value) => {
    	if (key === 'name') {
    		return value + '@'
    	}
    	if (key === 'age') {
    		return value + 1
    	}
    	return value
    })
    
    console.log(str)
    
  5. 结果如图:
    在这里插入图片描述

stringify 方法之 space

  1. 此方法除了第二个参数还存在第三个参数(space),此参数的作用为指定缩进用的空白字符串,用于美化输出

  2. 当 space 是一个数字时:它代表有多少的空格;上限为 10; 该值若小于 1,则意味着没有空格,如下:

    const obj = {
    	name: '张三',
    	age: 18,
    	friends: [
    		{ name: '李四', age: 20 },
    		{ name: '王五', age: 22 }
    	],
    	hobbies: ['篮球', '足球', '乒乓球']
    }
    
    // 正常转换
    const str1 = JSON.stringify(obj)
    console.log('正常转换: ', str1)
    
    // 2个空格
    const str2 = JSON.stringify(obj, null, 2)
    console.log('2个空格: ', str2)
    
  3. 结果如图:

    在这里插入图片描述

  4. 此时输出的结果,就不是单纯的一行字符串,而是经过美化的格式,在一些调试查看数据的时候,还是非常好用的

  5. 当 space 是一个字符串时:则每一级别会比上一级别多缩进该字符串(或该字符串的前 10 个字符),如下:

    const obj = {
    	name: '张三',
    	age: 18,
    	friends: [
    		{ name: '李四', age: 20 },
    		{ name: '王五', age: 22 }
    	],
    	hobbies: ['篮球', '足球', '乒乓球']
    }
    
    // 正常转换
    const str1 = JSON.stringify(obj)
    console.log('正常转换: ', str1)
    
    // 空格时
    const str2 = JSON.stringify(obj, null, ' ')
    console.log('空格时: ', str2)
    
    // 使用制表符(\t)来缩进
    const str3 = JSON.stringify(obj, null, '\t')
    console.log('制表符(\t): ', str3)
    
    // 字符长度超出 10
    const str4 = JSON.stringify(obj, null, 'aaabbbcccdddeee')
    console.log('字符长度超出 10: ', str4)
    
  6. 正常转换时,如图:

    在这里插入图片描述

  7. 空格时,如图:

    在这里插入图片描述

  8. 制表符时,如图:

    在这里插入图片描述

  9. 字符长度超出 10 时,如图:

    在这里插入图片描述

stringify 方法之 toJSON

如果一个被序列化的对象拥有 toJSON 方法,那么该 toJSON 方法就会覆盖该对象默认的序列化行为:不是该对象被序列化,而是调用 toJSON 方法后的返回值会被序列化

  1. 这个方法还是很好理解的,就是原来是转换原对象,但是如果有这个方法的话就会以我们这个方法的返回值为基准,如下:

    const obj = {
    	name: '张三',
    	age: 18,
    	friends: [
    		{ name: '李四', age: 20 },
    		{ name: '王五', age: 22 }
    	],
    	hobbies: ['篮球', '足球', '乒乓球'],
    	toJSON: function () {
    		// 返回数字
    		return 111
    	}
    }
    
    console.log('toJSON: ', JSON.stringify(obj))
    
  2. 结果如图:

    在这里插入图片描述

  3. 同样,可以更换为其他对象,如下:

    const obj = {
    	name: '张三',
    	age: 18,
    	friends: [
    		{ name: '李四', age: 20 },
    		{ name: '王五', age: 22 }
    	],
    	hobbies: ['篮球', '足球', '乒乓球'],
    	toJSON: function () {
    		// 返回数字
    		return {
    			name: '李白',
    			descripton: '一个浪漫的人'
    		}
    	}
    }
    
    console.log('toJSON: ', JSON.stringify(obj, null, 2))
    
  4. 结果如图:

    在这里插入图片描述

parse 方法之 reviver

  1. reviver 也是一个函数,执行时机在在 parse 函数返回之前,所以也可也来进行拦截或者说修改解析前的原始值

  2. 使用如下:

    const str = `{"name":"张三","age":18,"friends":[{"name":"李四","age":20},{"name":"王五","age":22}],"hobbies":["篮球","足球","乒乓球"]}`
    
    const obj = JSON.parse(str, (key, value) => {
    	if (key === 'age') {
    		return value + 2
    	}
    	return value
    })
    console.log(obj)
    
  3. 输出如图:

    在这里插入图片描述

  4. 在生成的对象之后,我们也可以发现,年龄是发生了变化的

利用 stringify 和 parse 实现深拷贝

  1. stringify 和 parse 搭配使用的时候,可以完成深拷贝,不敢存在一些限制,比如函数,循环引用,symbol 等等一些清空都是无法使用这种方式完成深拷贝的

  2. 只需要先使用 stringify 方法将对象转为 JSON 字符串,在使用 parse 方法进行解析即可,配合使用如下:

    const obj = {
    	name: '张三',
    	age: 18,
    	friends: [
    		{ name: '李四', age: 20 },
    		{ name: '王五', age: 22 }
    	],
    	hobbies: ['篮球', '足球', '乒乓球']
    }
    
    const obj2 = JSON.parse(JSON.stringify(obj))
    console.log('obj2: ', obj2)
    
    console.log('修改 obj2 的 name 属性的值为田七')
    
    obj2.name = '田七'
    
    console.log('obj: ', obj)
    console.log('obj2: ', obj2)
    
  3. 结果如图:

    在这里插入图片描述

  4. 可以看到,obj 并没有因为修改了 obj2 的值而受到影响,在一些简单的 JSON 形式的数据的对象时,使用此方法是一种非常不错的选择

文章来源:https://blog.csdn.net/qq_53109172/article/details/135305239
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。