你需要了解的JSON.stringify()

JSON.stringify()

最近在帮公司面试,就会问到克隆,深拷贝和浅拷贝,深拷贝回答的最多的是通过JSON.parse()JSON.stringify()来进行深拷贝的,然后就顺着话问一些JSON.stringify()的问题,就基本上没有说出来的了。基本只说把JSON对象转为JSON字符串

比如:
一个对象,说出JSON.stringify()之后的值

let dataObj = {
	a: '1',
	b: undefined,
	c: function() {
	    return 'this is function';
  	}
}
let dataStr = JSON.stringify(dataObj);
//dataStr的输出的值为多少

然后各种答案都有,报错、不输出、原样输出等。

然后定义一个数组,说出JSON.stringify()之后的值

let arrObj = [["1", undefined, function fun() {
    return true
}]
let arrStr = JSON.stringify(arrObj);
//输出的值

回到正题:

1、JSON.stringify()语法
JSON.stringify(value[, replacer [, space]])

JSON.stringify()不是只有一个参数,它最多可以有三个参数,只是一般后面两个用不到所以,大家都下意识的忽略。

参数
1. value

将要序列化成 一个 JSON 字符串的值。

2. replacer [可选]

如果该参数是一个函数,则在序列化过程中,被序列化的值的每个属性都会经过该函数的转换和处理;如果该参数是一个数组,则只有包含在这个数组中的属性名才会被序列化到最终的 JSON 字符串中;如果该参数为 null 或者未提供,则对象所有的属性都会被序列化。

3. space [可选]

指定缩进用的空白字符串,用于美化输出(pretty-print);如果参数是个数字,它代表有多少的空格;上限为10。该值若小于1,则意味着没有空格;如果该参数为字符串(当字符串长度超过10个字母,取其前10个字母),该字符串将被作为空格;如果该参数没有提供(或者为 null),将没有空格。

JSON.stringify()将值转换为相应的JSON格式:
  1. 转换值如果有 toJSON() 方法,该方法定义什么值将被序列化。
  2. 非数组对象的属性不能保证以特定的顺序出现在序列化后的字符串中。
  3. 布尔值、数字、字符串的包装对象在序列化过程中会自动转换成对应的原始值。
  4. undefined、任意的函数以及 symbol 值,在序列化过程中会5. 被忽略(出现在非数组对象的属性值中时)或者被转换成 null(出现在数组中时)。函数、undefined 被单独转换时,会返回 undefined,如JSON.stringify(function(){}) or JSON.stringify(undefined).
  5. 对包含循环引用的对象(对象之间相互引用,形成无限循环)执行此方法,会抛出错误。
  6. 所有以 symbol 为属性键的属性都会被完全忽略掉,即便 replacer 参数中强制指定包含了它们。
  7. Date 日期调用了 toJSON() 将其转换为了 string 字符串(同Date.toISOString()),因此会被当做字符串处理。
  8. NaNInfinity 格式的数值及 null 都会被当做 null
  9. 其他类型的对象,包括 Map/Set/WeakMap/WeakSet,仅会序列化可枚举的属性。
举例
1. toJSON
let a = {
    a: 1,
    toJSON: function () {
        return '哈哈哈。你怎么转都是这个'
    }
}
JSON.stringify(a)
//""哈哈哈。你怎么转都是这个""

转换值如果有 toJSON() 函数,该函数返回什么值,序列化结果就是什么值,并且忽略其他属性的值。

2. 非数组对象的属性不能保证以特定的顺序出现在序列化后的字符串中
//对象
JSON.stringify({
    a: function () {
        return '哈哈哈'
    },
    b: 1,
    c: undefined
})
/**
*"{
*  "b": 1
*}"
*/

//数组
JSON.stringify([function toJSON() {return '哈哈哈'}, 1, '', undefined])
//"[null,1,"",null]"
3. 自动转换成对应的原始值
JSON.stringify([new Number(1), new String("true"), new Boolean(false)]);
//"[1,"true",false]"
4. undefined、函数、symbol转化

作为对象属性值时:

let data = {
  a: "1",
  b: undefined,
  c: Symbol("c"),
  fn: function() {
    return 'this is JSON.stringfy';
  }
};
JSON.stringify(data)
//"{"a":"1"}"

undefined、函数、symbol作为对象属性值JSON.stringify() 会忽略对它们的序列化

作为数组元素值时:

let arr = ["1", undefined, function c() {
    return 'this is JSON.stringfy'
}, Symbol('d')]
JSON.stringify(arr)
//"["1",null,null,null]"

undefined、函数、symbol作为数组元素时,JSON.stringify()会将他们转为null

单独转换时:

JSON.stringify(function a (){console.log('this is JSON.stringfy')})
JSON.stringify(undefined)
JSON.stringify(Symbol('symbol'))
//三者都是undefined

单独的值进行转化时会返回 undefined

5. 对象之间相互引用,形成无限循环,会抛出错误。

这个就没啥说的了,无限循环…

报错信息贴一下
无限引用报错
谷歌翻译

6. symbol 为属性键的属性都会被完全忽略掉
let symbolObj = {
	[Symbol('test')]: "stringify"
}
JSON.stringify(symbolObj)
//"{}"

// 第二个参数replacer
JSON.stringify(symbolObj, function(k, v) {
    if (typeof k == 'symbol') {return 'is symbol'}
})
//undefined

//toJSON
let symbolObj2 = {
	[Symbol('test')]: "stringify",
	toJSON: function () {
		return 'to JSON 来强制转换'
	}
}
JSON.stringify(symbolObj2)
//to JSON 来强制转换

symbol 为属性键的属性都会被完全忽略掉, replacer 指定也不行。

7. Date
JSON.stringify(new Date())
//""2020-08-06T07:03:30.155Z""
JSON.stringify({a: new Date()})
//"{"a":"2020-08-06T07:03:55.952Z"}"
8. NaNInfinitynull
JSON.stringify(NaN)
JSON.stringify(null)
JSON.stringify(Infinity)
//三者都是null
9. Map/Set/WeakMap/WeakSet
let mapa = new Map()
mapa.set('a', 10)
let mapb = new WeakMap()
mapb.set({a: 1}, 10)
let seta = new Set()
seta.add(10)
let setb = new WeakSet()
setb.add({a: 1})
JSON.stringify(mapa)
JSON.stringify(mapb)
JSON.stringify(seta)
JSON.stringify(setb)
//全为 "{}"

let enumerableObj = Object.create(
   null, 
    { 
        x: { value: '不能枚举', enumerable: false },
        y: { value: '可以枚举', enumerable: true }
    }
)
JSON.stringify(enumerableObj)
// "{"y":"可以枚举"}"
//不可枚举的属性被忽略了

//用 replacer 第二参数看下
JSON.stringify(enumerableObj, (k, v) => {
	console.log('k的值:', k, 'v的值:', v)
	return v
})
// k的值:  v的值: {y: "可以枚举", x: "不能枚举"}
// k的值: y v的值: 可以枚举
//结果
// "{"y":"可以枚举"}"

在这里插入图片描述

2、replacer参数

replacer 参数可以是一个函数或者一个数组。作为函数,它有两个参数,键(key)和值(value),它们都会被序列化。如果 replacer 是一个数组,数组的值代表将被序列化成 JSON 字符串的属性名。

在开始时, replacer 函数会被传入一个空字符串作为 key 值,代表着要被 stringify 的这个对象。随后每个对象或数组上的属性会被依次传入。

函数应当返回JSON字符串中的value, 如下所示:

  • 如果返回一个 Number, 转换成相应的字符串作为属性值被添加入 JSON 字符串。
  • 如果返回一个 String, 该字符串作为属性值被添加入 JSON 字符串。
  • 如果返回一个 Boolean, "true" 或者 "false" 作为属性值被添加入 JSON 字符串。
  • 如果返回任何其他对象,该对象递归地序列化成 JSON 字符串,对每个属性调用 replacer 方法。除非该对象是一个函数,这种情况将不会被序列化成 JSON 字符串。
  • 如果返回 undefined,该属性值不会在 JSON 字符串中输出。

总结:
replacer作为数组时,会按照数组内的元素返回,如果作为函数时,你想它返回什么他就返回什么

1. replacer作为函数时
let obj = {
  a: "1",
  b: undefined,
  c: Symbol("c"),
  fn: function() {
    return 'test replacer';
  }
};
JSON.stringify(obj, (k, v) => {
	console.log(k, v)
	if (typeof v === 'undefined') {
		return 'this is undefined'
	} else if (typeof v === 'symbol') {
		return 'this is symbol'
	} else if (typeof v === 'function') {
		return 'this is function'
	} else {
		return v
	}
})
//打印的值

//第一个参数不是对象的第一个键值对,而是空字符串作为 key 值,value 值是整个对象的键值对
//'' {a: "1", b: undefined, c: Symbol(c), fn: ƒ}
//a 1
//b undefined
//c Symbol(c)
//fn ƒ () {
//    return 'test replacer';
//  }

//JSON.stringify()输出的值
/**
*"{
*  "a": "1",
*  "b": "this is undefined",
*  "c": "this is symbol",
*  "fn": "this is function"
*}"
*/

第一个参数不是对象的第一个键值对,而是空字符串作为 key 值,value 值是整个对象的键值对

2. replacer作为数组时

数组的值就代表了将被序列化成 JSON 字符串的属性名

let obj = {a: 1, c: 3, d: 4, b: 2}
JSON.stringify(obj, ['a', 'b', 'c'])
//"{"a":1,"b":2,"c":3}"

用途:数组对象去重

可以先把数组对象按照需要的值进行JSON.stringify(val, []),在进行字符串的比较。

3、space参数

space 参数用来控制结果字符串里面的间距。如果是一个数字, 则在字符串化时每一级别会比上一级别缩进多这个数字值的空格(最多10个空格);如果是一个字符串,则每一级别会比上一级别多缩进该字符串(或该字符串的前10个字符)。

let obj = {a: 1, b: 2, c: 3}
JSON.stringify(obj)
//"{"a":1,"b":2,"c":3}"
//作为数字时
JSON.stringify(obj, null, 2)
//"{↵  "a": 1,↵  "b": 2,↵  "c": 3↵}"
/**
*"{
*  "a": 1,
*  "b": 2,
*  "c": 3
*}"
*/
//作为字符串时
JSON.stringify(obj, null, 'add')
//"{↵add"a": 1,↵add"b": 2,↵add"c": 3↵}"
/**
*"{
*add"a": 1,
*add"b": 2,
*add"c": 3
*}"
*/
JSON.parse(JSON.stringify(obj))是一种将JavaScript对象转换为JSON字符串再转回JavaScript对象的常见方法。在这个过程中,JSON.stringify()方法将JavaScript对象转换为JSON字符串,而JSON.parse()方法则将JSON字符串转换回JavaScript对象。 这种方法的主要用途是在JavaScript中对对象进行深拷贝。通过先将对象转换为JSON字符串,然后再将其转换回对象,可以创建一个原始对象的副本,而不是只是引用原始对象。 例如,假设我们有一个包含复杂嵌套结构的JavaScript对象obj,我们想要创建它的副本。我们可以使用JSON.parse(JSON.stringify(obj))来实现这一目标。 这种方法的好处是它可以处理几乎所有类型的JavaScript对象,包括数组、函数和日期对象等。 但需要注意的是,JSON.stringify()方法会忽略对象的某些属性,例如函数和原型链上的属性。因此,通过JSON.parse(JSON.stringify(obj))进行深拷贝时,可能会丢失一些对象的特定行为。 此外,在使用JSON.parse()和JSON.stringify()方法时,需要确保处理的对象是有效的JSON格式。如果对象中包含不支持的数据类型或循环引用,这些方法可能会导致错误。 总结起来,JSON.parse(JSON.stringify(obj))是一种将JavaScript对象转换为JSON字符串再转回JavaScript对象的方法,用于实现对象的深拷贝。但需要注意处理的对象应为有效的JSON格式,并且一些特定类型的属性可能会丢失。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [了解 JSON.parse() 和 JSON.stringify()](https://blog.csdn.net/allway2/article/details/123856863)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *3* [关于JSON.parse(),JSON.stringify(),jQuery.parseJSON()的用法](https://download.csdn.net/download/weixin_38743391/13002642)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

gqkmiss

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值