谨慎使用JSON.stringify
谨慎使用JSON.stringify
为了避免因为对象是引用类型而造成的数据源污染,我们通常使用 JSON.stringify 将其转换为字符串,而后通过JSON.parse方法将字符串转化一个新对象来实现深拷贝。但是在这个过程中也会存在一些问题,本文就介绍一下使用JSON.stringify可能遇到的一些问题,尽可能在以后避免这些问题。
先看一段代码:
let obj = {name: 'leo',age: Infinity
}
let originObj = JSON.stringify(obj)
console.log(originObj) // {"name":"leo","age":null}
可以看到在转换过程中Infinity变成了null。
先看看解决办法:
- 简单粗暴,重新赋值
age属性 - 使用
JSON.stringify的第二个参数
function censor(key, value) {if (value === Infinity) {return "Infinity";}return value;
}
const b = JSON.stringify(obj, censor);const c = JSON.parse(b,function (key, value) {return value === "Infinity" ? Infinity : value;}
);
console.log(c); // {name: 'leo', age: Infinity}
作为参考,大家可能直接用了第一种方法。但是这里可以看到
JSON.stringify其实还有第二个参数,那么它有什么用呢?接下来我们就来揭开它的神秘面纱。
JSON.stringify 的基本语法
语法:
JSON.stringify(value[, replacer [, space]])
JSON.stringify()方法将JavaScript对象或值转换为JSON字符串,如果指定了替换函数,则可选择替换值;如果指定了替换数组,则可选择仅包含指定的属性。
简单来说,JSON.stringify() 将一个值转换为相应的 JSON 格式的字符串。
参数替换器
也就是第二个参数(replacer),该参数是可选的,可以是函数或数组。
当是函数时,在序列化过程中,每个待序列化的属性都会被函数进行转换处理。
let replacerFun = function (key, value) {console.log(key, value)if (key === 'name') {return undefined}return value
}let myIntro = {name: 'leo',age: 25,like: 'FE'
}console.log(JSON.stringify(myIntro, replacerFun))
// {"age":25,"like":"FE"}
这实际上是一个过滤函数,它利用了JSON.stringify中的特性,如果对象属性值未定义,则在序列化时会被忽略(稍后我们会提到)。
在开始时,replacer 函数将传递一个空字符串作为键值,代表要字符串化的对象。
上面console.log(key, value)输出的值如下:
{name: 'leo', age: 25, like: 'FE'} // 其实是 '' {name: 'leo', age: 25, like: 'FE'}, 不过''是个空字符
ame leo
age 25
like FE
{"age":25,"like":"FE"}
可见,通过第二个参数,我们可以更加灵活地操作和修改序列化目标的值。
当第二个参数是数组时,只会序列化数组中包含的属性名称:
JSON.stringify (myIntro, [ 'name' ]) // {"name":"leo"}
第三个参数
指定一个空字符串进行缩进,更常见的是指定一个数字,代表几个空格。
console.log(JSON.stringify(myIntro))
console.log(JSON.stringify(myIntro, null, 2))// 输出
// {"name":"leo","age":25,"like":"FE"}
// {
// "name": "leo",
// "age": 25,
// "like": "FE"
// }
JSON.stringify使用场景
判断对象/数组值是否相等
let a = [1,2,3],b = [1,2,3];
JSON.stringify(a) === JSON.stringify(b);// true
localStorage/sessionStorage 存储对象
我们知道localStorage/sessionStorage只能存储字符串。当我们要存储对象时,需要使用 JSON.stringify 将其转换为字符串,然后在获取对象时使用 JSON.parse解析出来。
function setLocalStorage(key,val) {window.localStorage.setItem(key, JSON.stringify(val));
};function getLocalStorage(key) {let val = JSON.parse(window.localStorage.getItem(key));return val;
};
实现对象深拷贝
let myIntro = {name: 'leo',age: 25,like: 'FE'
}function deepClone() {return JSON.parse(JSON.stringify(myIntro))
}let copyMe = deepClone(myIntro)
copyMe.like = 'js only'
console.log(myIntro, copyMe)// { name: 'leo', age: 25, like: 'FE' } { name: 'leo', age: 25, like: 'js only' }
路由(浏览器地址)参数传递
由于浏览器参数只能通过字符串传递,所以还需要JSON.stringify。
使用 JSON.stringify 的注意事项
在某些场景下使用 JSON.stringify 可能会引发一些难以发现的问题:
转换属性值中有toJSON方法
如果转换值中有toJSON方法,则该方法返回的值将是最终的序列化结果。
let toJsonMyIntro = {name: "Gopal",age: 25,like: "FE",toJSON: function () {return "frontend";},
};console.log(JSON.stringify(toJsonMyIntro)); // "frontend"
转换后的值中有未定义、任意函数、符号值
分为两种情况:
一种是数组对象,未定义的、任意函数和符号值都会被转换为null。
JSON.stringify([undefined, Object, Symbol("")]);
// '[null,null,null]'
一种是非数组对象,序列化时会被忽略。
JSON.stringify({ x: undefined, y: Object, z: Symbol("") });
// '{}'
对于这些情况,我们可以使用JSON.stringify的第二个参数来使其满足我们的期望。
const testObj = { x: undefined, y: Object, z: Symbol("test") }const resut = JSON.stringify(testObj, function (key, value) {if (value === undefined) {return 'undefined'} else if (typeof value === "symbol" || typeof value === "function") {return value.toString()}return value
})console.log(resut)
// {"x":"undefined","y":"function Object() { [native code] }","z":"Symbol(test)"}
含有循环引用的对象
let objA = {name: "leo",
}let objB = {age: 25,
}objA.age = objB
objB.name = objA
JSON.stringify(objA)
上面的代码会报错: VM1140:11 Uncaught TypeError: Converting circular structure to JSON
以symbol为属性键的属性
所有使用符号作为键控的属性都将被完全忽略,即使它们必须包含在替换参数中。
JSON.stringify({ [Symbol.for("foo")]: "foo" }, [Symbol.for("foo")])
// '{}'JSON.stringify({ [Symbol.for("foo")]: "foo" }, function (k, v) {if (typeof k === "symbol") {return "a symbol";}
})
// undefined
值为NaN和Infinity
数组值或具有 NaN 和 Infinity 值的非数组对象属性将转换为 null
let me = {name: "leo",age: Infinity,money: NaN,
};
let originObj = JSON.stringify(me);
console.log(originObj); // {"name":"leo","age":null,"money":null}JSON.stringify([NaN, Infinity])
// [null,null]
具有不可枚举的属性值
默认情况下,不可枚举属性被忽略。
let person = Object.create(null, {name: { value: "leo", enumerable: false },age: { value: "25", enumerable: true },
})console.log(JSON.stringify(person))
// {"age":"25"}
相关文章:
谨慎使用JSON.stringify
谨慎使用JSON.stringify 为了避免因为对象是引用类型而造成的数据源污染,我们通常使用 JSON.stringify 将其转换为字符串,而后通过JSON.parse方法将字符串转化一个新对象来实现深拷贝。但是在这个过程中也会存在一些问题,本文就介绍一下使用…...
驱动开发day8
编写LED灯的驱动,使用GPIO子系统,里面添加按键的中断处理 1.应用程序发送指令控制LED亮灭 2.按键1 按下,led1电位反转 按键2按下,led2电位反转 按键3 按下,led3电位反转 驱动程序 #include <linux/init.h> #i…...
CAS 机制
问题分析与思考: CAS 是 Java 中 Unsafe 类里面的方法,它的全称是 CompareAndSwap,比较并交换 的意思。 它的主要功能是能够保证在多线程环境下,对于共享变量的修改的原子性。 举个例子,比如说有这样一个场景ÿ…...
#P1003. [NOIP2009普及组] 道路游戏
题目描述 小新正在玩一个简单的电脑游戏。 游戏中有一条环形马路,马路上有 nn 个机器人工厂,两个相邻机器人工厂之间由一小段马路连接。小新以某个机器人工厂为起点,按顺时针顺序依次将这 nn 个机器人工厂编号为 1\sim n1∼n,因…...
python-网络爬虫.regular
regular 正则表达式 (regular expression) 正则表达式(regular expression)描述了一种字符串匹配的模式 (pattern), 可以用来检查一个串是否含有某种子串、将匹配的子串替换或者从某个串 中取出符合某个条件的子串等。 正则表达式是由普通…...
手动搭建gateway,项目集成gateway实现Token效果
目录 背景步骤1、首先创建springboot项目2、引入依赖3、配置文件!!!!!(超级重要!!!根据自己的需要进行配置)4、相关类我们在服务中进行的白名单中接口的操作如…...
linux下SVN服务器搭建
在本教程中,我们将介绍如何在Linux系统下搭建Subversion(SVN)服务器。Subversion是一种流行的版本控制系统,它允许多个人在同一项目上进行协作,同时避免了他们各自的更改发生冲突。 安装SVN 在大多数Linux发行版中&am…...
技术等级 TRL 定义
“不同环境、不同目标下TRL表述不一样” 技术等级 TRL 定义 TRL1 基本原理提出和发现 TRL2 技术应用研究 TRL3 完成概念验证,如叶栅试验、燃烧室头部试验等 TRL4 完成模拟部件试验.如压气机性能试验,燃烧室扇形试验 TRL5 完…...
DHorse v1.3.0 发布,基于k8s的发布平台
综述 DHorse是一个简单易用、以应用为中心的云原生DevOps系统,具有持续集成、持续部署、微服务治理等功能,无需安装依赖Docker、Maven、Node等环境即可发布Java、Vue、React应用,主要特点:部署简单、操作简洁、功能快速。 新增特…...
Redis - 缓存的双写一致性
概念: 当修改了数据库的数据也要同时更新缓存的数据,缓存和数据库的数据要保持一致 那为什么会有不一致的情况呢? 如果不追求一致性,正常有两种做法 先修改数据库 后删除旧的缓存先删除旧的缓存 再修改数据库 我们以先删除旧的…...
opencv03-Mat矩阵API的使用
opencv03-Mat矩阵API的使用 构造方法(具体介绍看API文档) int main() {Mat m1 Mat(200, 100, CV_8UC1);imshow("o1", m1);Mat m2 Mat(Size(100, 200), CV_8UC1);imshow("o2", m2);Mat m3 Mat(200, 100, CV_8UC3, Scalar(255, 0, 0));imshow("o3&…...
2023届浙江大学MPA提面A资格经验总结分享
本人是去年报考的浙大MPA项目,并通过提面获得了A资格,新一年浙大MPA项目提前批面试已经开始了,受达立易考周老师邀请来分享下我的提面经验,希望我的经验能对还在迷茫中的小伙伴有所帮助。 点开提面通知,首先看到…...
BugKu CTF(杂项篇MISC)—想要种子吗
BugKu CTF(杂项篇MISC)—想要种子吗 提 示: 描 述:flag{} 题目下载后是一张图片,打开如下。 一、工具 十六进制编辑器010 editor kali系统文件分离工具binwalk或者foremost 维吉尼亚密码 STEGHIDE图片隐写工具 文章所需的软件下载地址 ARCHPR压缩包密码破解…...
类之间的关系
1、类关系 继承、实现、依赖、组合、聚合 继承:一个类继承另一个类; 实现:一个类实现另一个接口; 依赖:一个类作为另一个的局部变量,方法的参数,临时对象等; 组合:一个类…...
【蓝图】p40-p43对象引用、变量有效性、实现键盘控制物体自转、简单点名系统
p40-p43对象引用、变量有效性、实现键盘控制物体自转、简单点名系统 p40对象引用、变量有效性p41实现键盘控制物体自转创建bool值控制旋转实现通过键盘控制自转 p42p43简单点名系统Get All Actors Of Class(获得场景中所有该类的actor演员)getFor Each L…...
vscode设置远程登录和免密登录
首先,我们去官网下载VScode 安装过程比较简单,大家自行安装即可,注意建议安装在除C盘外的其他盘中。 安装完成后,打开我们下载好的VScode,点击左侧的Extensions选项,搜索Remote,Install第一项R…...
今日头条面试真题及答案,软件测试工程师面试秘籍
试题1.在浏览器地址栏里输入一个网址,接下来会发生什么? 答案:发生的操作如下。 (1)浏览器查找该网址的IP地址。 (2)浏览器根据解析得到的IP地址向Web服务器发送一个HTTP请求。 &am…...
JavaScript Windows 浏览器对象模型
Window 对象 BOM 的核心就是 window 对象所有浏览器都支持 window 对象。它表示浏览器窗口。所有 JavaScript 全局对象、函数以及变量均自动成为 window 对象的成员。全局变量是 window 对象的属性。全局函数是 window 对象的方法。HTML DOM 的 document 也是 window 对象的属…...
【uniapp 获取缓存及清除缓存】
小程序及H5 获取缓存: 使用uniapp中的wx.getStorageInfoSync()方法可以获取当前小程序或H5应用的本地缓存信息,如下所示: let storageInfo uni.getStorageInfoSync() console.log(storageInfo)其中,storageInfo是一个对象&…...
【vim 学习系列文章 2 - vim 常用插件配置】
文章目录 1.1 vim 常用插件1.1.1 vim 插件 Pathogen 管理1.1.2 vim 常用插件推荐1.1.3 vim Leaderf1.1.4 vim ripgrep 工具1.1.5 vim Leaderf 配合 rg1.1.6 vim autocmd 配置 1.2 其它类型文件 vimrc 配置1.2.1 System Verilog vimrc 配置 上篇文章:vim 学习系列文章…...
未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?
编辑:陈萍萍的公主一点人工一点智能 未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?RWM通过双自回归机制有效解决了复合误差、部分可观测性和随机动力学等关键挑战,在不依赖领域特定归纳偏见的条件下实现了卓越的预测准…...
Docker 离线安装指南
参考文章 1、确认操作系统类型及内核版本 Docker依赖于Linux内核的一些特性,不同版本的Docker对内核版本有不同要求。例如,Docker 17.06及之后的版本通常需要Linux内核3.10及以上版本,Docker17.09及更高版本对应Linux内核4.9.x及更高版本。…...
rknn优化教程(二)
文章目录 1. 前述2. 三方库的封装2.1 xrepo中的库2.2 xrepo之外的库2.2.1 opencv2.2.2 rknnrt2.2.3 spdlog 3. rknn_engine库 1. 前述 OK,开始写第二篇的内容了。这篇博客主要能写一下: 如何给一些三方库按照xmake方式进行封装,供调用如何按…...
SciencePlots——绘制论文中的图片
文章目录 安装一、风格二、1 资源 安装 # 安装最新版 pip install githttps://github.com/garrettj403/SciencePlots.git# 安装稳定版 pip install SciencePlots一、风格 简单好用的深度学习论文绘图专用工具包–Science Plot 二、 1 资源 论文绘图神器来了:一行…...
前端导出带有合并单元格的列表
// 导出async function exportExcel(fileName "共识调整.xlsx") {// 所有数据const exportData await getAllMainData();// 表头内容let fitstTitleList [];const secondTitleList [];allColumns.value.forEach(column > {if (!column.children) {fitstTitleL…...
【项目实战】通过多模态+LangGraph实现PPT生成助手
PPT自动生成系统 基于LangGraph的PPT自动生成系统,可以将Markdown文档自动转换为PPT演示文稿。 功能特点 Markdown解析:自动解析Markdown文档结构PPT模板分析:分析PPT模板的布局和风格智能布局决策:匹配内容与合适的PPT布局自动…...
Matlab | matlab常用命令总结
常用命令 一、 基础操作与环境二、 矩阵与数组操作(核心)三、 绘图与可视化四、 编程与控制流五、 符号计算 (Symbolic Math Toolbox)六、 文件与数据 I/O七、 常用函数类别重要提示这是一份 MATLAB 常用命令和功能的总结,涵盖了基础操作、矩阵运算、绘图、编程和文件处理等…...
让AI看见世界:MCP协议与服务器的工作原理
让AI看见世界:MCP协议与服务器的工作原理 MCP(Model Context Protocol)是一种创新的通信协议,旨在让大型语言模型能够安全、高效地与外部资源进行交互。在AI技术快速发展的今天,MCP正成为连接AI与现实世界的重要桥梁。…...
浅谈不同二分算法的查找情况
二分算法原理比较简单,但是实际的算法模板却有很多,这一切都源于二分查找问题中的复杂情况和二分算法的边界处理,以下是博主对一些二分算法查找的情况分析。 需要说明的是,以下二分算法都是基于有序序列为升序有序的情况…...
在web-view 加载的本地及远程HTML中调用uniapp的API及网页和vue页面是如何通讯的?
uni-app 中 Web-view 与 Vue 页面的通讯机制详解 一、Web-view 简介 Web-view 是 uni-app 提供的一个重要组件,用于在原生应用中加载 HTML 页面: 支持加载本地 HTML 文件支持加载远程 HTML 页面实现 Web 与原生的双向通讯可用于嵌入第三方网页或 H5 应…...
