本文系统梳理了JavaScript中JSON.stringify()方法的三种参数用法,包括基础序列化、过滤器函数及缩进控制。同时探讨了其在判断对象相等、本地存储及深拷贝中的实际应用,并重点分析了NaN、undefined、循环引用及不可枚举属性等导致序列化失败或数据丢失的常见陷阱,帮助开发者规避潜在Bug。
一、使用方法
1、基本用法
JSON.stringify()函数的核心作用是将JavaScript对象转换为标准的JSON字符串格式。
let json1 = {
title: "Json.stringify",
author: [
"浪里行舟"
],
year: 2021
};
let jsonText = JSON.stringify(json1);
在默认情况下,该函数输出的JSON字符串不包含任何额外的空格或缩进,因此生成的jsonText变量值通常是一行紧凑的字符串。
"{"title":"Json.stringify","author":["浪里行舟"],"year":2021}"
在序列化JavaScript对象的过程中,所有的函数定义和原型链成员都会被有意忽略。此外,如果某个属性的值为undefined,该属性也会从结果中被剔除。最终生成的字符串仅包含所有实例属性且符合有效JSON数据类型的部分。
JSON.stringify()方法支持接收三个参数,其中后两个参数(即第二个和第三个参数)为可选参数。利用这两个可选参数,开发者可以指定更复杂的对象序列化策略。第二个参数用于充当过滤器,其类型可以是数组或函数;第三个参数则用于控制输出JSON字符串的缩进格式。通过单独或组合使用这些参数,能够更精细地掌控JSON序列化的行为。
2、第二个参数--过滤器
当第二个参数被指定为一个数组时,JSON.stringify()返回的结果将仅包含该数组中明确列出的对象属性。例如以下代码所示:
let json1 = {
title: "Json.stringify",
author: [
"浪里行舟"
],
year: 2021,
like: 'frontend',
weixin: 'frontJS'
};
let jsonText = JSON.stringify(json1, ['weixin']);
在此示例中,JSON.stringify()的第二个参数是一个包含字符串"weixin"的数组。该字符串对应待序列化对象中的特定属性,因此最终生成的JSON字符串中仅会保留这一属性。
"{"weixin":"frontJS"}"
若第二个参数是一个函数,其行为机制则有所不同。该回调函数接收两个参数:属性名(key)和属性值(value)。开发者可以根据传入的key来决定对相应属性执行何种操作。需要注意的是,key始终为字符串类型,但当value不属于任何键值对时,key为空字符串。
const students = [
{
name: 'james',
score: 100,
}, {
name: 'jordon',
score: 60,
}, {
name: 'kobe',
score: 90,
}
];
function replacer (key, value) {
if (key === 'score') {
if (value === 100) {
return 'S';
} else if (value >= 90) {
return 'A';
} else if (value >= 70) {
return 'B';
} else if (value >= 50) {
return 'C';
} else {
return 'E';
}
}
return value;
}
console.log(JSON.stringify(students, replacer, 4))
在上述代码中,我们通过replacer函数将百分制的成绩转换为了对应的成绩等级。

需要特别注意的是,当stringify的第二个参数为函数时,如果该函数的返回值为undefined,则对应的属性不会被序列化;若返回其他类型的值,则使用返回值替代原属性值进行序列化。
3、第三个参数--字符串缩进
JSON.stringify()的第三个参数用于控制输出的缩进格式和空格数量。当该参数为数值时,它表示每一级缩进所包含的空格数。例如,若希望每级缩进4个空格,可以按以下方式操作:
let json1 = {
title: "Json.stringify",
author: [
"浪里行舟"
],
year: 2021
};
let jsonText = JSON.stringify(json1, null, 4);
此时生成的jsonText格式如下所示:
{
"title": "Json.stringify",
"author": [
"浪里行舟"
],
"year": 2021
}
JSON.stringify()在处理数据时兼顾了数据转换与可读性,尽管在实际开发中,便于阅读的格式化输出这一特性常被忽视。
4、toJSON()方法--自定义JSON序列化
在某些场景下,对象需要在JSON.stringify()的基础上实现自定义的序列化逻辑。此时,可以在待序列化的对象中定义toJSON()方法,序列化过程将基于该方法返回适当的JSON表示。
以下对象通过添加toJSON()方法实现了自定义序列化:
let json1 = {
title: "Json.stringify",
author: [
"浪里行舟"
],
year: 2021,
like: 'frontend',
weixin: 'frontJS',
toJSON: function () {
return this.author
}
};
console.log(JSON.stringify(json1)); // ["浪里行舟"]
需要注意的是,不能使用箭头函数来定义toJSON()方法。主要原因是箭头函数的词法作用域绑定的是全局作用域,这在此场景下并不适用。
二、使用场景
1、判断数组是否包含某对象,或者判断对象是否相等。
//判断数组是否包含某对象
let data = [
{name:'浪里行舟'},
{name:'前端工匠'},
{name:'前端开发'},
],
val = {name:'浪里行舟'};
console.log(JSON.stringify(data).indexOf(JSON.stringify(val)) !== -1);//true
我们还可以利用JSON.stringify()方法来判断两个对象是否完全相等。
// 判断对象是否相等
let obj1 = {
a: 1,
b: 2
}
let obj2 = {
a: 1,
b: 2,
}
console.log(JSON.stringify(obj1) === JSON.stringify(obj2)) // true
然而,这种方式存在较大的局限性:如果对象的键顺序发生调整,判断结果将会出错。
// 调整对象键的位置后
let obj1 = {
a: 1,
b: 2
}
let obj2 = {
b: 2,
a: 1,
}
console.log(JSON.stringify(obj1) === JSON.stringify(obj2)) // false
2、使用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;
};
// 测试
setLocalStorage('Test',['前端工匠','浪里行舟']);
console.log(getLocalStorage('Test'));

3、实现对象深拷贝
在开发过程中,为了避免修改原数据,我们常需要深拷贝一份数据以进行任意操作。使用JSON.stringify()配合JSON.parse()来实现深拷贝是一个不错的选择。
let arr1 = [1, 3, {
username: ' kobe'
}];
let arr2 = JSON.parse(JSON.stringify(arr1));
arr2[2].username = 'duncan';
console.log(arr1, arr2)

该方法利用JSON.stringify将对象转换为JSON字符串,再通过JSON.parse将字符串解析回对象。经过这一来一回的操作,生成了一个新的对象,新对象会开辟新的栈空间,从而实现了深拷贝。
尽管这种方法可以实现数组或对象的深拷贝,但它无法正确处理函数和正则表达式。因为经过JSON.stringify和JSON.parse处理后,正则表达式将变为空对象,函数将变为null。
let arr1 = [1, 3, function () { }, {
username: ' kobe'
}];
let arr2 = JSON.parse(JSON.stringify(arr1));
arr2[3].username = 'duncan';
console.log(arr1, arr2)

三、使用注意事项
JSON.stringify()虽然功能强大,但部分属性无法被正确序列化。因此在开发中需注意以下几种情况,以免产生意想不到的Bug。
1、被转换值中有 NaN 和 Infinity
let myObj = {
name: "浪里行舟",
age: Infinity,
money: NaN,
};
console.log(JSON.stringify(myObj));
// {"name":"浪里行舟","age":null,"money":null}
JSON.stringify([NaN, Infinity])
// [null,null]
2、被转换值中有 undefined、任意的函数以及 symbol 值
这分为两种情况处理:
- 对于数组,undefined、任意函数以及symbol值在序列化过程中会被转换为null。
JSON.stringify([undefined, function () { }, Symbol("")]);
// '[null,null,null]'
- 对于非数组,undefined、任意函数以及symbol值在序列化过程中会被直接忽略。
JSON.stringify({ x: undefined, y: function () { }, z: Symbol("") });
// '{}'
3、循环引用
如果一个对象的属性值通过某种间接方式指向该对象本身,则构成循环引用。例如:
let bar = {
a: {
c: foo
}
};
let foo = {
b: bar
};
JSON.stringify(foo)
在这种情况下,序列化操作会报错:
// 错误信息
Uncaught ReferenceError: foo is not defined
at <anonymous>:3:8
4、含有不可枚举的属性值时
不可枚举的属性默认会被忽略处理:
let personObj = Object.create(null, {
name: { value: "浪里行舟", enumerable: false },
year: { value: "2021", enumerable: true },
})
console.log(JSON.stringify(personObj)) // {"year":"2021"}
四、总结
JSON.stringify()用于将JavaScript对象序列化为JSON字符串,该方法提供了一些选项来改变默认行为,从而实现过滤或修改流程。但也应注意,部分属性无法被stringify处理,因此在开发时应避开这些潜在陷阱。
以上就是JavaScript JSON.stringify()的使用总结的详细内容,更多关于JavaScript JSON.stringify()的使用的资料请关注本站其它相关文章!