JSON.stringify()基本使用与注意点
语法
JSON.stringfy(value[, replacer [, space]])
参数说明
- value:必需, 要转换的 JavaScript 值(通常为对象或数组)。
- replacer: 可选
- 用于转换结果的函数或数组;
- 如果 replacer 为函数,则 JSON.stringify 将调用该函数,并传入每个成员的键和值。使用返回值而不是原始值;
- 如果此函数返回 undefined,则排除成员。根对象的键是一个空字符串:""。如果 replacer 是一个数组,则仅转换该数组中具有键值的成员。成员的转换顺序与键在数组中的顺序一样。
- space:可选,文本添加缩进、空格和换行符,如果 space 是一个数字,则返回值文本在每个级别缩进指定数目的空格,如果 space 大于 10,则文本缩进 10 个空格。space 也可以使用非数字,使输出的格式更美化。
返回值
返回包含 JSON 文本的字符串。
基本使用
- JSON.stringify可以转换基本类型值(String,Boolean,Number)或引用类型对象(Object)数组(Array),我们平时使用最多的也是转换对象或数组;
- 可以指定replacer为函数选择性的地替换;
- 也可通过指定replacer为数组指定替换;
// 转换字符串
console.log(JSON.stringfy('Rylan')); // "Rylan"
// 转换数值
console.log(JSON.stringfy(18)); // "18"
// 转换布尔值
console.log(JSON.stringfy(true)); // "true"
// 转换对象
console.log(JSON.stringfy({name:'Rylan',age:18})); // "{'name':'Rylan','age':'18'}"
// 转换数组
console.log(JSON.stringfy(['Rylan',18])); // "['Rylan','18']"
// replacer函数选择性替换
console.log(JSON.stringfy({name:'Rylan',age:18},(key,value)=>{
return typeof age==='number'? value:undefined
})); // "{'name':'Rylan','age':'18'}"
//replacer指定数组
console.log(JSON.stringify({ name: 'Rylan', sex: 'male', age: 18 }, [ 'name' ])) //'{"name":"Rylan"}'
使用注意点
一开始使用JSON.stringfy没有多去注意应该注意的点,导致很多问题,
开始认识的时候只想到能使用就行,查看官网发现居然有这么多特性......
特性一
布尔值、数字、字符串的包装对象在序列化过程中会自动转换成对应的原始值;
console.log(JSON.stringfy('Rylan',18,true)) //"'Rylan','18','true'"
特性二
- 在对象中,
undefined、任意函数、symbol值在转换中会被忽略; - 在数组中,
undefined、任意函数、symbol值会转换为null; undefined、任意函数、symbol值单独转换会被直接转换为undefined;
// 对象中函数会被忽略
console.log(JSON.stringfy({
name:"Rylan",
age:18,
// 函数会被忽略
logMyName(){
console.log("my name is Rylan")
},
//undefined会被忽略
sex:undefined,
// Symbol会被忽略
symbolName: Symbol('前端胖头鱼')
}))
//"{'name':'Rylan,'age':'18'}"
//数组中存在着三种值会被转化为null
console.log(JSON.stringfy([
'Rylan',
18,
logMyName(){
console.log("my name is Rylan")
},
undefined,
Symbol("Rylan")
])
//"['Rylan','18',null,null,null]"
//单独转换为undefined
console.log(JSON.stringify( function logMyName () {
console.log('my name is Rylan')
} )) // undefined
console.log(JSON.stringify(undefined)) // undefined
console.log(JSON.stringify(Symbol('Rylan'))) // undefined
特性三
NaN 和 Infinity 格式的数值及null 都会被当做 null;
console.log(JSON.stringify({ age: NaN, age2: Infinity, name: null }))
//"{'age': null, 'age2': null, 'name': null}"
特性四
转换BigInt类型的值时会抛出错误;
const bigNumber = BigInt(1000000000000000n);
//呜噜噜...,这个都不知道这么读>>>>10个100万亿n~~~
console.log(JSON.stringify(bigNumber));
// TypeError: Do not know how to serialize a BigInt
特性五
转换值包含toJSON()方法,定义转换的值将被序列化;
const objToJSON = {
name: 'Rylan',
toJSON () {
return 'MY NAME IS RYLAN'
}
}
console.log(JSON.stringify(objToJSON.toJSON));
//'MY NAME IS RYLAN'
特性六
日期函数new Date()调用toJSON方法转换为字符串,也会被当做字符串处理;
let date=new Date();
//转换为字符串
console.log(date.toJSON()) //2021-12-01T00:00:00.932Z
console.log(JSON.stringify(date)) // "2021-12-01T00:00:00.932Z"
特性七
对包含循环利用,即对象之间相互引用的关系,形成无限循环,会抛出错误;
let loopObj = { name: 'Rylan', };
//引用关系导致无限赋值
loopObj.obj=loopObj;
console.log(JSON.stringify(loopObj))
// Converting circular structure to JSON
特性八
对于Map/Set/WeakMap/WeakSet此类型的对象,仅序列化其可枚举的属性;
let enumableObj={};
Object.defineProperties(enumerableObj, {
name: { value: 'Rylan', enumerable: true },
age: { value: 18, enumerable: false },
})
console.log(JSON.stringify(enumerableObj));
// '{"name":"Rylan"}'
特性九
对象中,以Symbol值作为键名会被直接忽略,就算使用replacer函数参数中重新定义值;
console.log(JSON.stringify({ [Symbol('Rylan')]: 'Rylan'} ));
// {}
console.log(JSON.stringify({
[ Symbol('Rylan') ]: 'Rylan', },
(key, value) => {
if (typeof key === 'symbol')
{ return value }
}))
// undefined
自己实现一个简单的JSON.stringify
function myJSONstringify(params) {
// console.log(params)
let type=typeof params;
// 用于获取完整的数据类型
function getType(data){
// 获取完整的数据类型
let type=Object.prototype.toString.call(data);
// 正则匹配并转换为小写
let result=type.replace(/\[object (.*?)\]/, '$1').toLowerCase()
return result
}
function isLoop(obj){
let bool=false;
let map=new Map();
function findLoop(obj){
Object.values(obj).forEach((value)=>{
if(typeof value==='object'){
if(map.has(value)){
return bool=true
}else{
map.set(value);
findLoop(value)
}
}
})
}
findLoop(obj)
return bool
}
// 判断是否是bigint类型,则抛出错误
if(type==='bigint'){
throw new TypeError('Do not know how to serialize a BigInt')
}
// 普通类型或传入值为null
if(type!=='object'||params===null){
// 非对象此三种特殊键会返回会null
let specialName=[NaN, Infinity, null];
// 非对象此三种基本的数据类型会返回undefined
let baseType=['undefined','function','symbol']
if(specialName.includes(params)){
// NaN 和 Infinity 格式的数值及null 都会被当做 null
return ""+null+""
}else if(baseType.includes(params)){
// undefined、任意函数、symbol值单独转换会被直接转换为undefined
return undefined
}else if(type==='string'){
// 布尔值、数字、字符串的包装对象在序列化过程中会自动转换成对应的原始值
return "'"+params+"'"
}else if(type==='number'||type==='boolean'){
// 布尔值、数字、字符串的包装对象在序列化过程中会自动转换成对应的原始值
return ""+params+""
}
}else{
let baseType=['undefined','function','symbol']
// 判断是数组
if(Array.isArray(params)){
// console.log(params);
let resultData=params.map(item=>{
if(baseType.includes(typeof item)){
// 在数组中, undefined、任意函数、symbol值会转换为null
return ""+null+""
}else{
// 递归调用,判断数组里面是否是对象或数组
return myJSONstringify(item)
}
})
return "["+resultData+"]"
}else{
// 对包含循环利用,即对象之间相互引用的关系,形成无限循环,会抛出错误;
if(isLoop(params)){
throw new TypeError('Converting circular structure to JSON')
}
// 转换值包含toJSON()方法,定义转换的值将被序列化
if (typeof params.toJSON === 'function') {
return myJSONstringify(params.toJSON())
}
let baseType=['undefined','function','symbol'];
let simpleType=['number','boolean']
if (simpleType.includes(getType(params))) {
return ""+params+""
} else if (getType(params) === 'string') {
return '"' + params + '"'
} else {
let resultData = [];
Object.keys(params).forEach((key) => {
//对象中,以Symbol值作为键名会被直接忽略,就算使用replacer函数参数中重新定义值;
if (typeof key !== 'symbol') {
const value = params[key]
// 在对象中, undefined、任意函数、symbol值在转换中会被忽略
if (!baseType.includes(typeof value)) {
resultData.push(`"${key}":${myJSONstringify(value)}`)
}
}
})
// console.log(resultData)
return `{${resultData}}`.replace(/'/, '"')
}
}
}
}
结尾
天啦了噜~,脑瓜子嗡嗡响的;以上就是对JSON.stringify的认识,便于方便记忆,以及实现,若有不足欢迎大家提出~~