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,则只会截取前十个字符;

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

相关推荐
okra-1 分钟前
Axure RP 10 进阶指南:从全局变量到JavaScript语法,打造高效原型设计!
javascript·axure·photoshop
默默学前端24 分钟前
ES6模板语法与字符串处理详解
前端·ecmascript·es6
lxh011332 分钟前
记忆函数 II 题解
前端·javascript
我不吃饼干39 分钟前
TypeScript 类型体操练习笔记(三)
前端·typescript
华仔啊43 分钟前
除了防抖和节流,还有哪些 JS 性能优化手段?
前端·javascript·vue.js
CHU7290351 小时前
随时随地学新知——线上网课教学小程序前端功能详解
前端·小程序
清粥油条可乐炸鸡1 小时前
motion入门教程
前端·css·react.js
这是个栗子1 小时前
【Vue3项目】电商前台项目(四)
前端·vue.js·pinia·表单校验·面包屑导航
前端Hardy1 小时前
Electrobun 正式登场:仅 12MB,JS 桌面开发迎来轻量化新方案!
前端·javascript·electron
树上有只程序猿1 小时前
新世界的入场券,不再只发给程序员
前端·人工智能