JSON.stringify的隐藏用法

关于JSON.stringify()最常见的用法,应该通过JSON.parse(JSON.stringify())来做对象的拷贝,但是关于JSON.stringify()实际还有很多用法。在开始之前,先来看一段简单的代码:

javascript 复制代码
JSON.stringify({
"reqId": "f67271bedd2041e79ed3754dcc5319db",
"partnerId": "P80000001",
"reqData": {
"issuerType": 1,
"issuerId": "9915",
"ticketDesc": "10减2元券",
"startTime": "2023-03-10",
"endTime": "2023-03-21",
"status": 0,
"hostInstNo": "",
"currPage": 1,
"pageSize": 100
},
"signType": "MD5",
"timestamp": "201809112345",
"sign": "EF7B56F75FA05FA07C8DB189518F0069"
}, null, 4)

可以看见,这段代码是没有格式化的,但是输出的结果却是正常空格格式化的。

这就是今天要说的关于JSON.stringify()的用法之一。

一、关于JSON.stringify的几个特性

1、JSON.stringify在处理undefined、函数、symbol、正则、Error特殊值时的不同表现

(1)、当undefined、函数、symbol三个特殊值作为对象属性值时:

javascript 复制代码
JSON.stringify({
    one: 'aaa',
    two: undefined,
    three: Symbol('333'),
    four: function(){
        return 1
    }
})

// 输出结果
'{"one":"aaa"}'

可以得出结论:当undefined、函数、symbol作为对象属性值时,JSON.stringify()会直接直接忽略掉

(2)、当undefined、函数、symbol三个特殊值作为数组元素时:

javascript 复制代码
JSON.stringify([1, 2, undefined, Symbol(3), function(){return 4}])

// 输出结果:
'[1,2,null,null,null]'

可以得出结论:当undefined、函数、symbol作为数组元素时,JSON.stringify()会直接将其序列化为null

(3)、当undefined、函数、symbol三个特殊值单独序列化时:

javascript 复制代码
JSON.stringify(undefined)
// 输出结果
undefined

JSON.stringify(Symbol('123'))
// 输出结果
undefined

JSON.stringify(function(){return true})
// 输出结果
undefined

可以得出结论:当undefined、函数、symbol单独进行序列化时,JSON.stringify()会直接将其序列化为undefined

(4)、当存在正则、Error对象时,无论是作为对象值、数组元素还是单独序列化,都只会返回空对象

css 复制代码
let obj = {
    a: 'a',
    b: 'b',
    reg: new RegExp('\w+'),
    err: new Error('error')
}
JSON.stringify(obj)

// 输出结果
'{"a":"a","b":"b","reg":{},"err":{}}' 

根据其这一特性,我们日常在使用深拷贝方法或者进行序列化的时候,就要考虑是否有这几种特殊类型值存在,如果存在需要用特殊方法处理(后边会介绍)

2、当转换值中有toJSON()方法时,序列化的结果就是该方法的返回值,会忽略掉其他属性。

javascript 复制代码
JSON.stringify({
    name: 'lilei',
    age: 12,
    toJSON: function(){
        return 'hanmeimei 14'
    }
})

// 输出结果
'"hanmeimei 14"'

3、对于Date的值,JSON.stringify()会正常输出

css 复制代码
JSON.stringify({time: new Date()})

// 输出结果
'{"time":"2024-04-01T08:18:39.722Z"}'

可以看到对于Date输出了正常的日期值,是因为Date对象内部有自己的toJSON()方法,相当于Date对象被当做了普通的字符串去处理。

4、对于NaN、Infinity、null,无论是作为对象的值、数组的元素还是单独序列化,都会被当做null

json 复制代码
JSON.stringify({
    one: NaN,
    twu: Infinity,
    three: null
})

// 输出结果
'{"one":"null","two":null,"three":null}'

5、如果存在属性可枚举和不可枚举的对象,仅会序列化可枚举属性

php 复制代码
JSON.stringify(
    Object.create(
        null,
        {
            a: { value: 'aaa', enumerable: false },
            b: { value: 'bbb', enumerable: true }
        }
    )
)

// 输出结果
'{"b":"bbb"}'

6、当使用JSPN.parse(JSON.stringify())进行对象拷贝时,注意循环引用问题,关于解决方法可以通过添加序列号、删除属性值、控制序列化深度等,具体情况具体分析。

二、关于JSON.stringify()的第二个和第三个参数

1、第二个参数replacer

第二个参数可以是一个数组,也可以是一个函数。

(1)当是数组时,数组的值代表着将被序列化成JSON字符串的属性名。

csharp 复制代码
let obj = {
    name: 'json',
    params: 'stringfy params'
}
JSON.stringify(obj, ['name'])

// 输出结果
'{"name":"json"}'

(2)当时函数时,可以改变上边说的相关特性,对于undefined、Symbol、函数类型(无论作为对象值、还是数组元素)、正则、Error,可以使其返回定义的值

javascript 复制代码
const data = {
  a: "aaa",
  b: undefined,
  c: Symbol("234"),
  fn: function() {
    return true;
  },
  reg: new RegExp('\w+'),
  err: new Error('error')
};

// 使用 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();
    case  Object . prototype . toString . call ( value) === "[object Error]":
      return 'error';
    case  Object . prototype . toString . call (value) === "[object RegExp]" :
      return 'regexp';
    default:
      break;
  }
  return value;
})

// 输出结果
'{"a":"aaa","b":"undefined","c":"Symbol(234)","fn":"function() {\n    return true;\n  }","reg":"regexp","err":"error"}'
// 未使用第二个参数时,只会输出 "{"a":"aaa"}" 

特殊情况:如果对象的属性是个Symbol,那么这个属性值也会直接被忽略掉,即使采用函数方法强制返回值也是无效的。

javascript 复制代码
JSON.stringify({[Symbol.for("json")]: "symbolstring"}, function(k, v) {
    if (typeof k === "symbol") {
      return v;
    }
})

// 输出结果
undefined

注意:replacer被传入为函数时,函数参数对应的第一对key/value并不是对象的第一个属性,key值是一个空字符串,value值是整个对象键值对;从第二个开始的key/value才是对应数据的属性值。

yaml 复制代码
const data = {  a : 2 ,  b : 3 ,  c : 4 ,  d : 5  }; JSON . stringify (data, ( key, value ) => {  console . log ( 'key:' , key, 'value:' , value);  return value; })

// console打印出内容
key:  value: {a: 2, b: 3, c: 4, d: 5}
key: a value: 2
key: b value: 3
key: c value: 4
key: d value: 5

2、第三个参数

第三个参数space主要用来控制结果的间距,或者是添加一些特殊标识。

javascript 复制代码
let obj = {
a: 1, b: 2, c: 3, d: 4
}
JSON.stringify(obj, null, 2)
JSON.stringify(obj, null, '**')

// 输出结果
' {
  "a" : 1 ,
  "b" : 2 ,
  "c" : 3 ,
  "d": 4
} '

'{
**"a": 1,
**"b": 2,
**"c": 3,
**"d": 4
}'

注意:space是有长度限制的,最大长度是10,但是超过10也不会报错。
如果传入的是数值并且超过10,其最多只会缩进10个空格; 如果传入的是字符串并且长度超过10,则只会截取前十个字符;

虽然日常开发中使用比较少,但是大概知道用法,在使用的时候还是很方便的~

相关推荐
吃杠碰小鸡35 分钟前
commitlint校验git提交信息
前端
虾球xz1 小时前
游戏引擎学习第20天
前端·学习·游戏引擎
我爱李星璇1 小时前
HTML常用表格与标签
前端·html
疯狂的沙粒1 小时前
如何在Vue项目中应用TypeScript?应该注意那些点?
前端·vue.js·typescript
小镇程序员2 小时前
vue2 src_Todolist全局总线事件版本
前端·javascript·vue.js
野槐2 小时前
前端图像处理(一)
前端
程序猿阿伟2 小时前
《智能指针频繁创建销毁:程序性能的“隐形杀手”》
java·开发语言·前端
疯狂的沙粒2 小时前
对 TypeScript 中函数如何更好的理解及使用?与 JavaScript 函数有哪些区别?
前端·javascript·typescript
瑞雨溪2 小时前
AJAX的基本使用
前端·javascript·ajax
力透键背2 小时前
display: none和visibility: hidden的区别
开发语言·前端·javascript