Open NieZhuZhu opened 4 years ago
// 使用 replacer 参数作为函数时
JSON.stringify(data, (key, value) => {
switch (true) {
case typeof value === "undefined":
return "undefined";
case typeof value === "symbol":
return value.toString();
case typeof value === "function":
return value.toString();
default:
break;
}
return value;
})
上述示例代码中switch,改成如下写法更优雅些。
// 使用 replacer 参数作为函数时
JSON.stringify(data, (key, value) => {
switch (typeof value) {
case "undefined":
return "undefined";
case "symbol":
return value.toString();
case "function":
return value.toString();
}
return value;
})
// 使用 replacer 参数作为函数时 JSON.stringify(data, (key, value) => { switch (true) { case typeof value === "undefined": return "undefined"; case typeof value === "symbol": return value.toString(); case typeof value === "function": return value.toString(); default: break; } return value; })
上述示例代码中switch,改成如下写法更优雅些。
// 使用 replacer 参数作为函数时 JSON.stringify(data, (key, value) => { switch (typeof value) { case "undefined": return "undefined"; case "symbol": return value.toString(); case "function": return value.toString(); } return value; })
这样改如何?
// 使用 replacer 参数作为函数时
JSON.stringify(data, (key, value) => {
switch (typeof value) {
case "undefined":
return "undefined";
case "symbol":
case "function":
return value.toString();
default:
return value;
}
});
or
JSON.stringify(data, (key, value) => (['undefined', 'symbol', 'function'].includes(typeof Value) ? String(value) : value));
学到了
你不知道的 JSON.stringify() 的威力
前言
其实有很多有用的东西,当时学习了,也记住了,但是时间久了就是记不住,所以导致在日常开发中总是想不起来原来这个东西可以这么用,而去选择了更加复杂和麻烦的方式。其实我们日常学习的知识就是拿来用的,即使你今天把知识点背下来了,没有去思考这个知识点我们可以用来干嘛,不需要几天就会慢慢地忘掉。所以今天我们来了解一下在日常学习时你遗漏掉或者忘掉或者没有思考过的你不知道的
JSON.stringify()
的威力。通过需求学习
JSON.stringify()
首先我们在开发的过程当中遇到这样一个处理数据的需求
我们需要将上面这个对象处理成下面这个对象
也就是在不改变属性的值的前提下,将对象属性修改一下。 把
_id
改成id
,把updated_at
改成updatedAt
,把created_at
改成createdAt
。我们现在通过这个小小的需求来见识一下JSON.stringify()
的强大吧。首先要解决这个问题我们有很多的解决方式,我们先提供两种不优雅的解决方案:
方案一完全没有问题可以实现。但是多声明了一个变量又加上一层循环并且还有很多的
if
else
语句,怎么都显得不太优雅。delete
属性和增加属性直接 delete 暴力解决太粗鲁了,而且有一个缺点,属性的顺序变了。
replace
美学典范瞬间感觉非常优雅和舒服,有木有!如果你这样写,你导师给你 review 代码的时候,你导师肯定会夸赞你的😁。
接下来,正片开始,我们今天将系统的学习或者说是复习一遍
JSON.stringify
的基础知识,让我们在日常开发中更加的游刃有余。温故知新之非常简单的
JSON.stringify()
九大特性JSON.stringify()
第一大特性对于
undefined
、任意的函数以及symbol
三个特殊的值分别作为对象属性的值、数组元素、单独的值时JSON.stringify()
将返回不同的结果。首先,我们来复习一下知识点,看一道非常简单的面试题目:请问下面代码会输出什么?
很简单这道题目面试官主要考察的知识点是:
undefined
、任意的函数以及symbol
作为对象属性值时JSON.stringify()
跳过(忽略)对它们进行序列化面试官追问:假设
undefined
、任意的函数以及symbol
值作为数组元素会是怎样呢?知识点是:
undefined
、任意的函数以及symbol
作为数组元素值时,JSON.stringify()
将会将它们序列化为null
我们再发挥动下脑筋,如果单独序列化这些值会是什么样的结果呢?
单独转换的结果就是:
undefined
、任意的函数以及symbol
被JSON.stringify()
作为单独的值进行序列化时都会返回undefined
JSON.stringify()
第一大特性总结undefined
、任意的函数以及symbol
作为对象属性值时JSON.stringify()
对跳过(忽略)它们进行序列化undefined
、任意的函数以及symbol
作为数组元素值时,JSON.stringify()
将会将它们序列化为null
undefined
、任意的函数以及symbol
被JSON.stringify()
作为单独的值进行序列化时,都会返回undefined
JSON.stringify()
第二大特性也是在使用过程中必须要非常注意的一个点:
正如我们在第一特性所说,
JSON.stringify()
序列化时会忽略一些特殊的值,所以不能保证序列化后的字符串还是以特定的顺序出现(数组除外)。JSON.stringify()
第三大特性toJSON()
函数,该函数返回什么值,序列化结果就是什么值,并且忽略其他属性的值。JSON.stringify()
第四大特性JSON.stringify()
将会正常序列化Date
的值。实际上
Date
对象自己部署了toJSON()
方法(同Date.toISOString()),因此Date
对象会被当做字符串处理。JSON.stringify()
第五大特性NaN
和Infinity
格式的数值及null
都会被当做null
。直接上代码:
JSON.stringify()
第六大特性关于基本类型的序列化:
JSON.stringify()
第七大特性关于对象属性的是否可枚举:
JSON.stringify()
第八大特性我们都知道实现深拷贝最简单粗暴的方式就是序列化:
JSON.parse(JSON.stringify())
,这个方式实现深拷贝会因为序列化的诸多特性导致诸多的坑点:比如现在我们要说的循环引用问题。这也就是为什么用序列化去实现深拷贝时,遇到循环引用的对象会抛出错误的原因。
JSON.stringify()
第九大特性最后,关于
symbol
属性还有一点要说的就是:symbol
为属性键的属性都会被完全忽略掉,即便replacer
参数中强制指定包含了它们。关于
replacer
是什么呢,它是JSON.stringify()
的第二个参数,我们比较少的会用到,所以很多时候我们会忘记JSON.stringify()
第二个、第三个参数,场景不多,但是用的好的话会非常的方便,关于JSON.stringify()
第九大特性的例子中对replacer
参数不明白的同学先别急,其实很简单,我们马上就会在下面的学习中弄懂。枕典席文之
JSON.stringify()
第二个参数和第三个参数强大的第二个参数
replacer
replacer
参数有两种形式,可以是一个函数或者一个数组。作为函数时,它有两个参数,键(key)和值(value),函数类似就是数组方法map
、filter
等方法的回调函数,对每一个属性值都会执行一次该函数。如果replacer
是一个数组,数组的值代表将被序列化成 JSON 字符串的属性名。replacer
作为函数时可以打破九大特性的大多数特性
第二个参数
replacer
非常强大,replacer
作为函数时,我们可以打破九大特性的大多数特性,我们直接来看代码吧。虽然使用 toString() 方法有点耍流氓的意思但是不得不说第二个参数很强大。
传入
replacer
函数的第一个参数需要注意的是,replacer 被传入的函数时,第一个参数不是对象的第一个键值对,而是空字符串作为 key 值,value 值是整个对象的键值对:
实现
map
函数我们还可以用它来手写实现一个对象的类似 map 的函数。
replacer
作为数组时replacer
作为数组时,结果非常简单,数组的值就代表了将被序列化成 JSON 字符串的属性名。有意思却没啥用的第三个参数
space
space
参数用来控制结果字符串里面的间距。首先看一个例子就是到这东西到底是干啥用的:上面代码一眼就能看出第三个参数的作用了,花里胡哨的,其实这个参数还是比较鸡肋的,除了好看没啥特别的用处。我们用
\t
、\n
等缩进能让输出更加格式化,更适于观看。如果是一个数字, 则在字符串化时每一级别会比上一级别缩进多这个数字值的空格(最多10个空格);
如果是一个字符串,则每一级别会比上一级别多缩进该字符串(或该字符串的前10个字符)。
总结
JSON.stringify()
九大特性:一、对于
undefined
、任意的函数以及symbol
三个特殊的值分别作为对象属性的值、数组元素、单独的值时的不同返回结果。undefined
、任意的函数以及symbol
作为对象属性值时JSON.stringify()
对跳过(忽略)它们进行序列化undefined
、任意的函数以及symbol
作为数组元素值时,JSON.stringify()
将会将它们序列化为null
undefined
、任意的函数以及symbol
被JSON.stringify()
作为单独的值进行序列化时都会返回undefined
二、非数组对象的属性不能保证以特定的顺序出现在序列化后的字符串中。
三、转换值如果有
toJSON()
函数,该函数返回什么值,序列化结果就是什么值,并且忽略其他属性的值。四、
JSON.stringify()
将会正常序列化Date
的值。五、
NaN
和Infinity
格式的数值及null
都会被当做null
。六、布尔值、数字、字符串的包装对象在序列化过程中会自动转换成对应的原始值。
七、其他类型的对象,包括 Map/Set/WeakMap/WeakSet,仅会序列化可枚举的属性。
八、对包含循环引用的对象(对象之间相互引用,形成无限循环)执行此方法,会抛出错误。
九、所有以
symbol
为属性键的属性都会被完全忽略掉,即便replacer
参数中强制指定包含了它们。JSON.stringify()
第二个参数和第三个参数强大的第二个参数:
map
、filter
等方法的回调函数,对每一个属性值都会执行一次该函数(期间我们还简单实现过一个map
函数)。replacer
是一个数组,数组的值代表将被序列化成 JSON 字符串的属性名。华丽的第三个参数:
如果是一个数字, 则在字符串化时每一级别会比上一级别缩进多这个数字值的空格(最多10个空格)。
如果是一个字符串,则每一级别会比上一级别多缩进该字符串(或该字符串的前10个字符)。
注意:
第一个例子的方案三,有小伙伴提示说这个方案会有风险,确实是这样的(可能会把对象的值给替换掉)。大家慎用吧,大部分情况下这样使用是 ok 的。小伙伴们提供的第四种方案还是很不错的:
推荐阅读
面试官连环追问:数组拍平(扁平化) flat 方法实现