JSON.stringify()与JSON.parse()没有你想的那样简单

news2024/11/17 1:34:18

重新学习这两个API的起因

在本周五有线上的项目,16:30开始验证线上环境。
开始都是顺顺利利,一帆风顺。
大概17:50左右,我正在收拾东西。
准备下班去王者峡谷骑着我的船溜达一圈。
可是天降意外,给我派了一个bug。
测试给我说:有一条数据的详情页有数据但是在页面中没有显示数据。
不可能,绝对不可能。当时我信誓旦旦的。蛮自信。
当时怀疑是这条数据本身就没有详细数据。用户还没有补充详情。
但是测试给我发了一张图片。
我看见控制台出现红色的 Uncaught SyntaxError
映入我的眼球,感觉就像在向我宣战:
此时我虚了,感觉十有八九就是一个bug。
后来经过排查,发现是 JSON.string()引起的。
故而,今天周六简单记录一下 JSON.string它并不是我们想的那样简单。

大家对 JSON.string() 的第一印象是什么?

我现在依稀记得:
JSON.stringify() 方法将一个 JavaScript 对象或值转换为 JSON 字符串。
其他的就没有什么特别的印象。
其实,它在对不同类型数据处理时,会做出不同的反应。
下面坐好我在峡谷买的船,一起来看一下。

JSON.string()转换的值中有 toJSON() 方法,那么返回值直接替代当前这个对象

var obj = {
  name:'小魔神',
  like:'喜欢和乌鸦说话',
  toJSON: function () {
      return '活下去';
  }
};
var newStr = JSON.stringify(obj);
console.log(newStr);
此时,你认为输出的值是什么?
认真考虑10s。是什么?
最后会输出  '活下去'
是不是很意外,是不是很惊喜。竟然是这个结果。
这的是我们都没有想到对吧?
子所以这这个结果:
因为:obj这个对象中有  toJSON()方法。
那么这个方法的返回值将会替代当前这个对象。所以是 '活下去'

有 toJSON() 方法没有返回值会怎么样?

有的小伙伴这个时候就在想了。
你说的是因为转换中有 toJSON()方法并且有返回值(retuen)才会替代当前的对象。
如果有 toJSON()方法但是没有返回值是不是就不会替换当前这个对象了呢?
于是我们写下了这样的代码
let obj = {
  name: '小魔神',
  like: '喜欢和乌鸦说话',
  toJSON: function() {
    console.log('我没有返回值')
  }
};
let newStr = JSON.stringify(obj);
console.log(newStr);

大家觉得是输出什么结果?
思考5s钟,你觉得是啥?
输出 undefined。为什么是undefined呢?
因为函数没有返回值的时候,默认返回 undefined
也就是说:
toJSON: function() {
  return undefined
  console.log('我没有返回值')
}
你以为 JSON.stringify 的神奇之处只有这点。
那你就错了,它有很多我们之前可能没有了解的地方。
我们接着往下看,看看还有什么什么黑魔法

无法序列化错误对象,错误对象将会被转为为空对象

// 创建了一个错误对象
const err = new Error('错的不是我,而是这个世道。')
let obj = {
		name:'小魔神',
		like:'喜欢和乌鸦说话',
		err
}; 
console.log(JSON.stringify(obj));
// 我们发现 err 这个错误对象变为了空对象 {}
是不是觉得 JSON.stringify 有点东西在里面了
我们继续往下看

对象中不可枚举的值将不会对其序列化

let obj = {
	name:'小魔神',
	like:'喜欢和乌鸦说话',
}; 
Object.defineProperty(obj, 'name', {
	value: '魔神',
	enumerable: false // 将它设置为不可枚举
})
// name属性将不会被输出。[因为不会对它进行器序列化]
console.log(JSON.stringify(obj)); 
---这里可以写一
是不是觉得 JSON.stringify 越来越有意思了。

NaN 和 Infinity 及 null 都会被当做 null

// 1.7976931348623157E+10308 是浮点数的最大上限值 显示为Infinity
// -1.7976931348623157E+10308 是浮点数的最小下限值 显示为-Infinity
const obj = {
    infinityMax: 1.7976931348623157E+10308,
    infinityMin: -1.7976931348623157E+10308,
		a: NaN
}
console.log('obj输出的值是:', JSON.stringify(obj)); 

日期对象将会对其序列化为字符串string

const obj = {
    dateTime: new Date(),
    name: '小魔神',
    like: '喜欢和乌鸦说话',
}
const objCopy = JSON.parse(JSON.stringify(obj));
// 发现类型是字符串
console.log('类型是', typeof objCopy.dateTime)
// 因为是字符串就无法调用原来日期的getTime时间戳了
console.log(objCopy.dateTime.getTime())

所以在序列化日期对象的时候千千万万要注意。
因为它会将日期对象最后变成字符串。
从而导致之前的日期方法不能够调用。

循环引用的对象将会抛出错误

const obj = {
	name:'小魔神',
	like:'喜欢和乌鸦说话',
	sex:null
}
obj.sex = obj; //我们这里循环引用了,将会报错
const objCopy = JSON.parse(JSON.stringify(obj));
console.log("objCopy", objCopy)

undefined、函数、symbol值 在不同的场合将会发生不同的反应

undefined、函数[方法]、symbol值在不同的场合,
将会发生不同的''化学反应'。
在对象中,作为Value值的时候,在序列的时候将会忽略。
在对象中,将会被转化为null。
单独转化时,将会变为undefined。

undefined、函数、symbol值,在序列化过程中会被忽略 【出现在非数组对象的属性值中时】

let person = Symbol('小魔神');
const obj = {
	person,
	un: undefined,
	funSy: () => { console.log('前端已死') }
}
const objCopy = JSON.parse(JSON.stringify(obj));
console.log("objCopy",objCopy)
我们发现  undefined、函数、symbol值,在序列化过程中会被忽略

undefined、任意的函数、symbol 值将会换成 null(出现在数组中时)

let person = Symbol('小魔神');
let sayFun = function () { console.log("我太难了") }
let arr =[ undefined, person, sayFun]
const objCopy = JSON.parse(JSON.stringify(arr));
console.log("objCopy",objCopy)

所以在进行拷贝的时候,需要特别注意一下。
方法[任意的函数]会被丢失。不能调用

函数、undefined,symbol 被单独转换时,会返回 undefined

let a1 = JSON.stringify(function() {})
let a2 = JSON.stringify(undefined)
let a3 = JSON.stringify(Symbol('小魔神'))
console.log(a1)
console.log(a2)
console.log(a3)

遨游一圈的感想

我们平时在开发中,更多的是使用JSON.string()和JSON.parse()。
对我们需要的数据进行拷贝。
在拷贝的过程中需要注意以上的情况。
否者可能出现翻车。
JSON.string()也单独用在 get 请求将数组进行序列化。
这个时候各位小伙伴也需要注意一下。避免一些值丢失或者发生变化
还有就是将数据存储在localStorage、sessionStorage也会使用JSON.string()
我们也需要注意一下

使用JSON.string() 需要注意的点

1.使用JSON.string() 转换的值中,如果有 toJSON() 方法,那么返回值直接代替了当前的这个对象 
2.有 toJSON() 方法没有返回值会返回 undefined
3.无法序列化错误对象,错误对象将会被转为为空对象 
4.对象中不可枚举的值将不会对齐序列化 
5.NaN 和 Infinity 及 null 都会被当做 null。
6.日期对象将会对其序列化为字符串string
7.循环引用的对象将会抛出错误
8.undefined、任意的函数、symbol 值,在序列化过程中会被忽略【出现在非数组对象的属性值中时】
或者被转换成 null(出现在数组中时)。
函数、undefined,symbol 被单独转换时,会返回 undefined

简单说下 JSON.parse()

我们之前都在介绍 JSON.string(),我们现在简单说下 JSON.parse()。
毕竟他们俩是一对好基友
JSON.parse() 方法用于将一个 JSON 字符串转换为对象。
那什么是 JSON字符串呢?
JSON 是一种按照 JavaScript 对象语法的数据格式,这是 Douglas Crockford 推广的。
虽然它是基于 JavaScript 语法,但它独立于 JavaScript。
这也是为什么许多程序环境能够读取(解读)和生成 JSON。
JSON.parse(jsonStr,[function])
参数说明:
jsonStr:必需, 一个有效的 JSON 字符串。
function: 可选,一个转换结果的函数, 将为对象的每个成员调用此函数。

JSON需要注意的点事项

1.JSON 是一种纯数据格式,它只包含属性,没有方法。[或者说方法会被丢失]
也就是说:如果你原来的某一个对象中包含方法,在使用JSON之后,该方法会被丢失的哈~

2.JSON 数据格式为键/值对。 
JSON 要求在键值对 key 和 属性名称value周围使用双引号。单引号无效。
否者会报错的哈。Uncaught SyntaxError  未捕获的语法错误

3.JSON 可以将任何标准合法的 JSON 数据格式化保存,不只是数组和对象。
比如,一个单一的字符串或者数字或者一个空数组可以是合法的 JSON 对象。
这一点(第3点)很多人认为与第2点互相矛盾。
第二点不是说的是键值对key和value吗?
怎么单一的字符串和空数组,数字也可以呢?
其实没有矛盾,你直接使用 JSON.parse([])这样肯定是不行的。会出现语法错误
但是你先使用 JSON.stringify([]) 然后在使用JSON.parse就可以了

4.在使用 JSON.parse的使用需要注意第一个参数是否是JSON字符串。
否者会出现转化失败

键值对必须使用双引号进行包裹,否则就会报错

let jsonStr = "{'name': '张老师', 'sex':'男'}";
let newArr = JSON.parse(jsonStr)
console.log(newArr )
// 上面使用的是单引号,会报错

// 下面使用的是双引号--不会报错
// let jsonStr = '{"a1": "Hello", "b1": "World"}';
// let newArr = JSON.parse(jsonStr)
// console.log(newArr )

ps:键值对必须使用双引号进行包裹这里还隐含了另外一个意思
就是说 key和value必须要都要有双引号包裹。否则就会出现语法错误

使用 JSON.parse() 必须要符合JSON字符串

从上面的理解中,我们知道了使用JSON.parse() 必须要符合JSON字符串。
下面的使用 JSON.parse() 将会报错、
非常重要的点:使用JSON.parse() 必须要符合JSON字符串
非常重要的点:使用JSON.parse() 必须要符合JSON字符串
非常重要的点:使用JSON.parse() 必须要符合JSON字符串
重要的事情说三遍

直接转换数组

<script>
	let oldObj= []
	let arr = JSON.parse(oldObj)
	console.log('parse', parse )
</script>
将会报错 
Uncaught SyntaxError: Unexpected end of JSON input at JSON.parse (<anonymous>)
Uncaught SyntaxError  未捕获的语法错误
因为:使用JSON.parse() 必须要符合JSON字符串。
然而oldObj= [] 不是一个字符串

非要转换数组

let strJSON = JSON.stringify([])
let newObj = JSON.parse(strJSON)
console.log('newObj', newObj ) // 输出的是 []
我们先使用JSON.stringify([])将它转化为JSON字符串就可以了

JSON.parse() 不允许用逗号作为结尾

JSON.parse("[10, 20, 30, 40, ]");
JSON.parse('{"name1" : "澹台烬", }');

尾声 

1.JSON 是一种纯数据格式,它只包含属性,没有方法。
2.JSON 要求在键值对 key 和 属性名称value周围使用双引号。单引号无效。
3.JSON 可以将任何标准合法的 JSON 数据格式化保存。
如:数组,对象,单一的字符串或者数字
4.JSON.parse() 不允许用逗号作为结尾
特别提醒:在使用 JSON.parse的使用需要注意第一个参数是否是JSON字符串。
如果你觉得我写的还不错:请我点一个推荐或者打赏。感谢各位大佬

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/838280.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

山西电力市场日前价格预测【2023-08-06】

日前价格预测 预测明日&#xff08;2023-08-06&#xff09;山西电力市场全天平均日前电价为411.77元/MWh。其中&#xff0c;最高日前电价为457.52元/MWh&#xff0c;预计出现在19: 30。最低日前电价为370.37元/MWh&#xff0c;预计出现在13: 15。 价差方向预测 1&#xff1a; 实…

海外应用商店优化实用指南之关键词

和SEO一样&#xff0c;关键词是ASO中的一个重要因素。就像应用程序标题一样&#xff0c;在Apple App Store和Google Play中处理应用程序关键字的方式也有所不同。 关键词研究。 对于Apple&#xff0c;我们的所有关键词只能获得100个字符&#xff0c;Google Play没有特定的关键…

数据结构10 -查找_树表查找

创建二叉搜索树 二叉搜索树 二叉搜索树是有数值的了&#xff0c;二叉搜索树是一个有序树。 若它的左子树不空&#xff0c;则左子树上所有结点的值均小于它的根结点的值&#xff1b; 若它的右子树不空&#xff0c;则右子树上所有结点的值均大于它的根结点的值&#xff1b; 它…

47.Linux学习day01 基础命令详解1(很全面)

目录 一、Linux和Windows的区别 二、Linux系统目录结构 常见目录说明 三、Linux常见的基础命令 1.pwd 2.cd 3.ls 4.man 5. touch 6.mkdir 7. rmdir 今天正式学习了linux的一些基础操作和基础知识&#xff0c;以及linux和windows的区别。 一、Linux和Windows的区…

SpringMVC基于SpringBoot的最基础框架搭建——包含数据库连接

SpringMVC基于SpringBoot的最基础框架搭建——包含数据库连接 背景目标依赖配置文件如下项目结构如下相关配置如下启动代码如下Controller如下启动成功接口调用成功 背景 工作做了一段时间&#xff0c;回忆起之前有个公司有线下笔试&#xff0c;要求考生做一个什么功能&#x…

建设全球研发中心城市,长沙与人才何以双向奔赴?

跨越山涧峡谷&#xff0c;需要搭建钢铁桥梁&#xff0c;跨越文化沟通&#xff0c;需要搭建互相理解的桥梁&#xff0c;那么&#xff0c;一座城市与人才之间的联系&#xff0c;应该搭建怎样的桥梁&#xff1f; 近日&#xff0c;长沙出台了重磅文件《中共长沙市委长沙市人民政府…

XSS漏洞原理及利用跨站请求伪造CSRF

XSS漏洞原理及利用&跨站请求伪造CSRF XSS一、案例二、什么是XSS三、XSS危害四、XSS的分类4.1、反射型XSS4.1.1、介绍4.1.2、利用过程 4.2、存储型XSS4.2.1、介绍4.2.2、利用过程4.2.3、案例 4.3、DOM型XSS4.3.1、介绍4.3.2、常用的DOM方法4.3.3、案例4.3.3.1、代码分析4.3.…

Spring源码之XML文件中Bean标签的解析1

读取XML文件&#xff0c;创建对象 xml文件里包含Bean的信息&#xff0c;为了避免多次IO&#xff0c;需要一次性读取xml文件中所有bean信息&#xff0c;加入到Spring工厂。 读取配置文件 new ClassPathResource("applicationContext.xml")ClassPathResource是Sprin…

vue动态生成行

vue代码 <el-table :data"form.lineInfos" :bordertrue style"width: 99.99%;"> <el-table-column type"index" label"序号" width"50"></el-table-column> <el-table-column prop"unitPrice&qu…

【Linux 网络】 传输层协议之TCP协议 TCP的三次握手和四次挥手

TCP协议 TCP协议段格式谈谈什么是 “可靠” 和 “不可靠”TCP协议段——序号与确认序号TCP协议段——窗口大小TCP协议段 —— 六个标志位确认应答机制&#xff08;ACK&#xff09;超时重传机制连接管理机制TCP 的三次握手四次挥手TCP三次握手四次挥手总结图 滑动窗口流量控制拥…

18. SpringBoot 如何在 POM 中引入本地 JAR 包

❤️ 个人主页&#xff1a;水滴技术 &#x1f338; 订阅专栏&#xff1a;成功解决 BUG 合集 &#x1f680; 支持水滴&#xff1a;点赞&#x1f44d; 收藏⭐ 留言&#x1f4ac; Spring Boot 是一种基于 Spring 框架的轻量级应用程序开发框架&#xff0c;它提供了快速开发应用程…

第126天:内网安全-隧道技术SSHDNSICMPSMB上线通讯LinuxMac

知识点 #知识点&#xff1a; 1、入站规则不出网上线方案 2、出站规则不出网上线方案 3、隧道技术-SMB&ICMP&DNS&SSH 4、控制上线-Linux&Mac&IOS&Android-连接方向&#xff1a;正向&反向&#xff08;基础课程有讲过&#xff09; -内网穿透&#xf…

vue2-vue项目中你是如何解决跨域的?

1、跨域是什么&#xff1f; 跨域本质是浏览器基于同源策略的一种安全手段。 同源策略&#xff08;sameoriginpolicy&#xff09;&#xff0c;是一种约定&#xff0c;它是浏览器最核心也是最基本的安全功能。 所谓同源&#xff08;即指在同一个域&#xff09;具有以下三个相同点…

Java对象的前世今生

文章目录 一、创建对象的步骤二、类加载机制三、内存分配指针碰撞 (内存连续)空闲列表 (内存不连续) 四、创建对象的5种方法五、浅拷贝与深拷贝 以下一行代码内部发生了什么&#xff1f; Person person new Person();一、创建对象的步骤 根据JLS中的规定&#xff0c;Java对象…

牢记这16个SpringBoot 扩展接口,写出更加漂亮的代码

1、背景 Spring的核心思想就是容器&#xff0c;当容器refresh的时候&#xff0c;外部看上去风平浪静&#xff0c;其实内部则是一片惊涛骇浪&#xff0c;汪洋一片。Springboot更是封装了Spring&#xff0c;遵循约定大于配置&#xff0c;加上自动装配的机制。很多时候我们只要引…

Scala编程语言入门教程

Scala教程 方便个人学习和查阅 学习目标 Scala介绍 简介 Scala创始人Martin Odersky马丁奥德斯基 再回到我们的scala语言&#xff0c;在Scala官网https://www.scala-lang.org/介绍了其六大特征。 Java和scala可以混编 类型推测(自动推测类型) 并发和分布式&#xff08;Ac…

nginx的优化和防盗链 重要!!!

实验一、隐藏版本号 要把nginx的版本号隐藏起来&#xff0c;防止恶意攻击 方法一&#xff1a;修改配置文件 在http模块中加入一个命令 server_token off&#xff1b; 过程&#xff1a; 备份&#xff0c;改配置文件一定要备份 修改配置文件 在http模块中添加 server_tokens …

城市与AI,正待济沧海

厦门&#xff0c;自古以来是海上丝绸之路的战略支点&#xff0c;是中国海洋贸易网络中的明珠。外来的理念与技术自厦门而入&#xff0c;中国的文化与商品自厦门而出。新事物、新科技往往在这里焕发最耀眼的生机——比如说&#xff0c;人工智能。 多年来&#xff0c;厦门持续推进…

外部排序算法总结

一.内排总结 在之前博客里&#xff0c;博主已经介绍了各种内部排序算法的原理和C语言代码实现&#xff0c;不懂的朋友可以在同系列专栏里选择查看&#xff0c;今天介绍常见排序算法的最后一点&#xff0c;也就是外部排序。在此之前&#xff0c;我们先对外部排序的各种算法做一…

Centos7/8 安装/配置 Redis5

目录 一、安装 Redis 二、创建符号链接 1.针对可执行程序设置符号链接 2.针对配置文件设置符号链接 三、修改配置文件 1.修改 ip 地址 2.关闭保护模式 四、设置工作目录 1.创建工作目录 2.在配置文件中&#xff0c;配置工作目录 五、设置日志文件 1.创建日志目录 2…