这篇“JSON.stringify与JSON.parse怎么实现”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“JSON.stringify与JSON.parse怎么实现”文章吧。
JSON 的 stringify
和 parse
两个方法在平时的工作中也很常用,如果没有一些特殊的类型,是实现数据深拷贝的一个原生方式。
下面就这两个方法的一个手动实现思路。
JSON.stringify 方法用于将 Javascript 值转换为 JSON 字符串。该方法有三个参数:
data: 需要转换的数据
replacer:用于转换结果的对象或者数组,可以函数或者数组
space:文本添加缩进、空格和换行符,可以是数字或者字符串,数字的最大值是 10,字符串的最大长度是 10
下面的测试只用到这些类型: number,string,function,object,array,null,undefined,map,set,weakmap,weakset
但是 Javascript 数据的严格类型远远不止这几个。
首先我们用 JSON.stringify 来打印结果:
const testJson = { 4: 3, n: 1, s: 's', f: () => { }, null: null, unde: undefined, arr: [1, 's', null, undefined, () => { }], obj: { n: '1', s: 's' }, map: new Map(), set: new Set([1, 2, 3]), wmap: new WeakMap(), wset: new WeakSet() } const raws = JSON.stringify(testJson) // { // "4":3,"n":1,"s":"s","null":null,"arr":[1,"s",null,null,null], // "obj":{"n":"1","s":"s"},"map":{},"set":{},"wmap":{},"wset":{} // }
根据上面的结果,我们可以发现对象内的 function
, undefined
被剔除了,map
, set
等都被动的转换成了空对象。而数组内的 function
和 undefined
被替换成了 null
。
所以我们可以根据上述规则写一个简单的 stringify
方法:
const stringify = (data: any) => { // 获取数据的严格类型 const type = getType(data) let res = '' switch (type) { case 'Object': // 处理对象 res = stringifyObject(data) break case 'Array': // 处理数组 res = stringifyArray(data) break case 'Number': case 'Boolean': res = `${data}` break case 'String': res = `"${data}"` break case 'Null': res = 'null' break case 'Set': case 'WeakSet': case 'Map': case 'WeakMap': res = '{}' break default: return } return res }
实现几个辅助函数:
// 获取严格类型 const getType = (data: any) => { return Object.prototype.toString.call(data).slice(8, -1) } // 处理对象方法 const stringifyObject = (data: Record) => { const vals: string[] = [] for (const key in data) { // 递归处理 const val = stringify(data[key]) // 如果值为 undefined,我们则需要跳过 if (val !== undefined) { vals.push(`"${key}":${val}`) } } return `{${vals.join(',')}}` } // 处理数组方法 const stringifyArray = (data: any[]) => { const vals: any[] = [] for (const val of data) { // 递归处理,如果返回 undefined 则替换为 null vals.push(stringify(val) || 'null') } return `[${vals.join(',')}]` }
到这里就实现了 stringify
的简单版本。下面可以简单测试一下:
const raws = JSON.stringify(testJson) const cuss = stringify(testJson) console.log(raws === cuss) // true
后面还有两个参数,我们先实现第三个,第二个参数的作用等下在实现。
space 主要是用于添加空格、换行、缩进,但是只要 space 的值是合法的,换行符是默认加上一个的。所以我们要改下 stringify 的方法:
type Replacer = ((key: string, value: any) => any) | null | (string | number)[] export const stringify = (data: any, replacer?: Replacer, space?: number | string, indent = 1) => { const type = getType(data) if (typeof space === &#39;number&#39;) { if (space <= 0) { space = undefined } else { space = Math.min(10, space) } } else if (typeof space === &#39;string&#39;) { space = space.substring(0, 10) } else if (space) { space = undefined } let res = &#39;&#39; switch (type) { case &#39;Object&#39;: res = stringifyObject(data, indent, replacer, space) break case &#39;Array&#39;: res = stringifyArray(data, indent, replacer, space) break // 省略部分代码 } // 省略部分代码 }
对于 space 的不同非法的值,我们可以在控制台上进行一些简单的测试就可以得出,像 -1
这种其实是不生效的。而我处理的是只能是数字和字符串,数字必须是 1 - 10,字符串的最长长度是 10 位,其余的都重置为 undefined。因为像数组和对象的这种嵌套,缩进其实是要跟着动的,这里就新增了 indent
字段,初始为 1,后续递归就 + 1。
// 新增分隔符处理方法 const handleSeparator = (space: number | string, indent: number, prefix: string = &#39;&#39;, suffix: string = &#39;&#39;) => { let separator = prefix + &#39;\n&#39; if (typeof space === &#39;number&#39;) { separator += &#39; &#39;.repeat(space).repeat(indent) } else { separator += space.repeat(indent) } return separator + suffix } // 对象方法修改 const stringifyObject = (data: Record, indent: number, replacer?: Replacer, space?: number | string) => { const vals: string[] = [] for (const key in data) { const val = stringify(data[key], replacer, space, indent + 1) if (val !== undefined) { vals.push(`"${key}":${space ? &#39; &#39; : &#39;&#39;}${val}`) } } // 新增 space 处理 if (space) { const val = vals.join(handleSeparator(space, indent, &#39;,&#39;)) if (!val) { return &#39;{}&#39; } const front = handleSeparator(space, indent, &#39;{&#39;) const back = handleSeparator(space, indent - 1, &#39;&#39;, &#39;}&#39;) return front + val + back } return `{${vals.join(&#39;,&#39;)}}` } // 数组处理方法 const stringifyArray = (data: any[], indent: number, replacer?: Replacer, space?: number | string) => { const vals: any[] = [] for (const val of data) { vals.push(stringify(val, replacer, space, indent + 1) || &#39;null&#39;) } // 新增 space 处理 if (space) { const front = handleSeparator(space, indent, &#39;[&#39;) const val = vals.join(handleSeparator(space, indent, &#39;,&#39;)) const back = handleSeparator(space, indent - 1, &#39;&#39;, &#39;]&#39;) return front + val + back } return `[${vals.join(&#39;,&#39;)}]` }
replacer 参数有两个类型:
数组类型是用来过滤对象类型内的字段,只保留数组内的 key
函数类型就是在数组和对象遍历的时候,开发者可以自定义某些类型的字符串方式
所以这里我们需要修改三处地方:
// 起始方法增加一个是否是第一次调用的标记 init export const stringify = (data: any, replacer?: Replacer, space?: number | string, indent = 1, init = true) => { // 如果 replacer 为函数的话,初始 key 为空串,值为 data if (typeof replacer === &#39;function&#39; && init) { return stringify(replacer(&#39;&#39;, data), replacer, space, indent, false) } const type = getType(data) // 省略部分代码 } const stringifyObject = (data: Record, indent: number, replacer?: Replacer, space?: number | string) => { const filter = getType(replacer) === &#39;Array&#39; ? replacer : null const vals: string[] = [] for (const key in data) { // 补全参数,修改 replacer 处理 const val = stringify( typeof replacer === &#39;function&#39; ? replacer(key, data[key]) : data[key], replacer, space, indent + 1, false ) if ( val !== undefined && ( !filter || (filter as (string | number)[]).includes(key) || (filter as (string | number)[]).includes(+key) ) ) { vals.push(`"${key}":${space ? &#39; &#39; : &#39;&#39;}${val}`) } } // 省略部分代码 } const stringifyArray = (data: any[], indent: number, replacer?: Replacer, space?: number | string) => { const vals: any[] = [] let i = 0 for (const val of data) { // 补全参数,修改 replacer 处理 vals.push(stringify( typeof replacer === &#39;function&#39; ? replacer(i++, val) : val, replacer, space, indent + 1, false ) || &#39;null&#39;) } if (space) { const front = handleSeparator(space, indent, &#39;[&#39;) const val = vals.join(handleSeparator(space, indent, &#39;,&#39;)) const back = handleSeparator(space, indent - 1, &#39;&#39;, &#39;]&#39;) return front + val + back } return `[${vals.join(&#39;,&#39;)}]` }
到这里, stringify 的方法差不多了。下面是完整代码:
type Replacer = ((key: string | number, value: any) => any) | null | (string | number)[] const getType = (data: any) => { return Object.prototype.toString.call(data).slice(8, -1) } const handleSeparator = (space: number | string, indent: number, prefix: string = &#39;&#39;, suffix: string = &#39;&#39;) => { let separator = prefix + &#39;\n&#39; if (typeof space === &#39;number&#39;) { separator += &#39; &#39;.repeat(space).repeat(indent) } else { separator += space.repeat(indent) } return separator + suffix } const stringifyObject = (data: Record, indent: number, replacer?: Replacer, space?: number | string) => { const filter = getType(replacer) === &#39;Array&#39; ? replacer : null const vals: string[] = [] for (const key in data) { const val = stringify( typeof replacer === &#39;function&#39; ? replacer(key, data[key]) : data[key], replacer, space, indent + 1, false ) if ( val !== undefined && ( !filter || (filter as (string | number)[]).includes(key) || (filter as (string | number)[]).includes(+key) ) ) { vals.push(`"${key}":${space ? &#39; &#39; : &#39;&#39;}${val}`) } } if (space) { const val = vals.join(handleSeparator(space, indent, &#39;,&#39;)) if (!val) { return &#39;{}&#39; } const front = handleSeparator(space, indent, &#39;{&#39;) const back = handleSeparator(space, indent - 1, &#39;&#39;, &#39;}&#39;) return front + val + back } return `{${vals.join(&#39;,&#39;)}}` } const stringifyArray = (data: any[], indent: number, replacer?: Replacer, space?: number | string) => { const vals: any[] = [] let i = 0 for (const val of data) { vals.push(stringify( typeof replacer === &#39;function&#39; ? replacer(i++, val) : val, replacer, space, indent + 1, false ) || &#39;null&#39;) } if (space) { const front = handleSeparator(space, indent, &#39;[&#39;) const val = vals.join(handleSeparator(space, indent, &#39;,&#39;)) const back = handleSeparator(space, indent - 1, &#39;&#39;, &#39;]&#39;) return front + val + back } return `[${vals.join(&#39;,&#39;)}]` } export const stringify = (data: any, replacer?: Replacer, space?: number | string, indent = 1, init = true): string | undefined => { if (typeof replacer === &#39;function&#39; && init) { return stringify(replacer(&#39;&#39;, data), replacer, space, indent, false) } const type = getType(data) if (typeof space === &#39;number&#39;) { if (space <= 0) { space = undefined } else { space = Math.min(10, space) } } else if (typeof space === &#39;string&#39;) { space = space.substring(0, 10) } else if (space) { space = undefined } let res = &#39;&#39; switch (type) { case &#39;Object&#39;: res = stringifyObject(data, indent, replacer, space) break case &#39;Array&#39;: res = stringifyArray(data, indent, replacer, space) break case &#39;Number&#39;: res = `${data}` break case &#39;Boolean&#39;: res = `${data}` break case &#39;String&#39;: res = `"${data}"` break case &#39;Null&#39;: res = &#39;null&#39; break case &#39;Set&#39;: case &#39;WeakSet&#39;: case &#39;Map&#39;: case &#39;WeakMap&#39;: res = &#39;{}&#39; break default: return } return res }
stringify
方法的实现还是比较简单的,在一些笔试中还有可能会有相关需要实现的题。
而 JSON.parse
则是需要将合法的 json 字符串转换成对象,这里就需要用到一个概念:有限状态自动机
这里只做简单的介绍:有限状态机(Finite State Machine),是指任意时刻都处于有限状态集合中的某一状态。当其获得一个输入字符时,将从当前状态转换到另一个状态或者仍然保持当前状态。
可以结合当前 json 字符串的场景来简单理解一下:
我们有如下一个字符串:
const str = &#39;{"4":3,"s":"s","null":null,"arr":[1,"s",null],"obj":{}}&#39;
然后定义几个状态:
const State = { INIT: &#39;INIT&#39;, // 初始状态 OBJECTSTART: &#39;OBJECTSTART&#39;, // 开始解析对象 ARRAYSTART: &#39;ARRAYSTART&#39;, // 开始解析数组 OBJVALSTART: &#39;OBJVALSTART&#39;, // 开始解析对象的属性与值 OBJVALEND: &#39;OBJVALEND&#39;, // 对象属性与值解析结束 ARRVALSTART: &#39;ARRVALSTART&#39; // 开始解析数组值 }
因为 json 字符串是非常规则的字符串,所以我们可以结合正则表达式来提取相关步骤的数据,在字符串中的 &#39; &#39;\t\n\r
等也是可以的,所以在正则中需要考虑并且替换。
const parse = (data: string | number | null || boolean) => { if (typeof data === &#39;number&#39; || data === null || typeof data === &#39;boolean&#39;) { return data } // 将字符串转换为地址引用,方便后面字符串数据的消费 const context = { data } // 具体解析方法 return parseData(context) }
然后定义几个辅助函数:
// 字符串的消费函数 - 就是截取已匹配完的数据,返回剩余字符串 const advance = (context: { data: string }, num: number) => { context.data = context.data.slice(num) } // 是否结束状态机 const isEnd = (ctx: { data: string }) => { // 如果没有数据了,则结束 if (!ctx.data) { return false } const match = /^([}\]])[ \t\n\r]*/.exec(ctx.data) if (match) { if ( match[1] === &#39;}&#39; && getType(res) !== &#39;Object&#39; || match[1] === &#39;]&#39; && getType(res) !== &#39;Array&#39; ) { throw Error(&#39;解析错误&#39;) } advance(ctx, match[0].length) return false } return true } // 处理值 const parseValue = (context: { data: string }, match: any[]) => { advance(context, match[0].length) const valMatch = /^"(.*?)"$/.exec(match[1]) if (valMatch) { return valMatch[1] } if (match[1] === &#39;null&#39;) { return null } if (match[1] === &#39;true&#39;) { return true } if (match[1] === &#39;false&#39;) { return false } if (isNaN(+match[1])) { throw Error(&#39;解析错误&#39;) } return Number(match[1]) } // 解析对象属性值 const parseObjValue = (context: { data: string }) => { const match = /^[ \n\t\r]*((".*?")|([0-9A-Za-z]*))[ \t\n\r]*/.exec(context.data) if (match) { return parseValue(context, match) } new Error(&#39;解析错误&#39;) } // 解析数组值 const parseArrValue = (context: { data: string }) => { const refMatch = /^({|\[[ \n\t\r]*)/.exec(context.data) if (refMatch) { return parseData(context) } const match = /^((".*?")|([0-9a-zA-Z]*))[ \n\t\r]*[,]?[ \n\t\r]*/.exec(context.data) if (match) { return parseValue(context, match) } throw Error(&#39;解析错误&#39;) }
在上面定义状态的时候,解析对象、数组和数组值的时候只有开始状态,而没有结束状态。只是结束状态统一放入 isEnd 函数中,。
下面开始定义 parseData
函数:
第一步
const parseData = (ctx: { data: string }) => { let res: any = &#39;&#39; let currentState = State.INIT while (isEnd(ctx, res)) { switch (currentState) { case State.INIT: { const match = /^[ \t\n\r]*/.exec(ctx.data) if (match?.[0].length) { advance(ctx, match[0].length) } if (ctx.data[0] === &#39;{&#39;) { res = {} currentState = State.OBJECTSTART } else if (ctx.data[0] === &#39;[&#39;) { res = [] currentState = State.ARRAYSTART } else { res = parseObjValue(ctx) } } break case State.OBJECTSTART: break case State.OBJVALSTART: break case State.OBJVALEND: break case State.ARRAYSTART: break case State.ARRVALSTART: break // no default } } return res }
INIT
中,先去掉前面的空格、换行等字符,示例:
// 消费前 const str1 = &#39; \t\n\r{"4":3,"s":"s","null":null,"arr":[1,"s",null],"obj":{}}&#39; // 消费后 const str2 = &#39;{"4":3,"s":"s","null":null,"arr":[1,"s",null],"obj":{}}&#39;
然后再判读第一个字符是什么:
如果是 {
,则将状态转移到 OBJECTSTART
,将 res
赋值一个空对象
如果是 [
,则将状态转移到 ARRAYSTART
,将 res
赋值一个空数组
如果都不是,则就是一个值,可以用对象解析属性值的方法来解析,判读是否是合法的字符串
所以这里的状态转移到了对象解析 OBJECTSTART
:
第二步
const parseData = (ctx: { data: string }) => { let res: any = &#39;&#39; let currentState = State.INIT while (isEnd(ctx)) { switch (currentState) { case State.INIT: // 省略部分代码 break case State.OBJECTSTART: { const match = /^{[ \t\n\r]*/.exec(ctx.data) if (match) { advance(ctx, match[0].length) currentState = State.OBJVALSTART } } break case State.OBJVALSTART: break case State.OBJVALEND: break case State.ARRAYSTART: break case State.ARRVALSTART: break // no default } } return res }
OBJECTSTART
中,消费掉 {
,将状态转移到 OBJVALSTART
, 剩余字符数据:
const str = &#39;"4":3,"s":"s","null":null,"arr":[1,"s",null],"obj":{}}&#39;
第三步
const parseData = (ctx: { data: string }) => { let res: any = &#39;&#39; let currentState = State.INIT while (isEnd(ctx)) { switch (currentState) { case State.INIT: // 省略部分代码 break case State.OBJECTSTART: // 省略部分代码 break case State.OBJVALSTART: { const match = /^"(.*?)"[ \n\t\r]*:[ \n\t\r]*/.exec(ctx.data) if (match) { advance(ctx, match[0].length) if (ctx.data[0] === &#39;{&#39; || ctx.data[0] === &#39;[&#39;) { res[match[1]] = parseData(ctx) } else { res[match[1]] = parseObjValue(ctx) } currentState = State.OBJVALEND } } break case State.OBJVALEND: break case State.ARRAYSTART: break case State.ARRVALSTART: break // no default } } return res }
先获取 key:
等数组并消费,剩余字符数据:
const str = &#39;3,"s":"s","null":null,"arr":[1,"s",null],"obj":{}}&#39;
先判读后续字符的第一个字符是什么:
如果是 {
或者 [
,则开启一个新的状态机
否则直接用 parseObjValue
解析值
最后将状态转移至 OBJVALEND
。
第四步
const parseData = (ctx: { data: string }) => { let res: any = &#39;&#39; let currentState = State.INIT while (isEnd(ctx)) { switch (currentState) { case State.INIT: // 省略部分代码 break case State.OBJECTSTART: // 省略部分代码 break case State.OBJVALSTART: // 省略部分代码 break case State.OBJVALEND: { const match = /^[ \t\n\r]*(,)[ \t\n\r]*/.exec(ctx.data) if (match) { if (match[1] === &#39;,&#39;) { currentState = State.OBJVALSTART } advance(ctx, match[0].length) } } break case State.ARRAYSTART: break case State.ARRVALSTART: break // no default } } return res }
如果后面匹配出来的字符是 ,
,则表示后续还有其它的对象属性,我们需要将状态重新转移到 OBJVALSTART
, 如果是其它的 }
或者 ]
,则会在此次消费完毕,然后在 isEnd
中会退出状态机。
后续剩余字符的变化会依照上数状态的变化而进行字符消费:
const str = &#39;3,"s":"s","null":null,"arr":[1,"s",null],"obj":{}}&#39; // 1 const str = &#39;,"s":"s","null":null,"arr":[1,"s",null],"obj":{}}&#39; // 2 const str = &#39;"s":"s","null":null,"arr":[1,"s",null],"obj":{}}&#39; // 省略 s 和 null // 3 开启新的状态机 const str = &#39;[1,"s",null],"obj":{}}&#39; // 4 结束状态机 const str = &#39;],"obj":{}}&#39; // 5 开启新的状态机 const str = &#39;{}}&#39; // 6 结束状态机 const str = &#39;}}&#39; // 7 结束状态机 const str = &#39;}&#39;
数组的处理
const parseData = (ctx: { data: string }) => { let res: any = &#39;&#39; let currentState = State.INIT while (isEnd(ctx)) { switch (currentState) { case State.INIT: // 省略部分代码 break case State.OBJECTSTART: // 省略部分代码 break case State.OBJVALSTART: // 省略部分代码 break case State.OBJVALEND: // 省略部分代码 break case State.ARRAYSTART: { const match = /^\[[ \t\n\r]*/.exec(ctx.data) if (match) { advance(ctx, match[0].length) currentState = State.ARRVALSTART } } break case State.ARRVALSTART: res.push(parseArrValue(ctx)) break // no default } } return res }
如果第一个字符为 [
,则会开启新的状态机,状态也会转换为 ARRAYSTART
,然后在 ARRAYSTART
状态内进行数组值的转换。
到这里整个 JSON.parse
的实现思路差不多,但是上述的流程应该有没考虑到的地方,但是大体差不多,只是边界的处理问题。测试示例:
// 数据使用上面的 testJson const raws = JSON.stringify(testJson) const rawp = JSON.parse(raws) const cusp = parse(raws) console.log(raws, &#39;JSON.stringify&#39;) console.log(rawp, &#39;JSON.parse&#39;) console.log(cusp, &#39;parse&#39;)
结果:
const State = { INIT: &#39;INIT&#39;, OBJECTSTART: &#39;OBJECTSTART&#39;, ARRAYSTART: &#39;ARRAYSTART&#39;, OBJVALSTART: &#39;OBJVALSTART&#39;, OBJVALEND: &#39;OBJVALEND&#39;, ARRVALSTART: &#39;ARRVALSTART&#39; } const isEnd = (ctx: { data: string }, res: any) => { if (!ctx.data) { return false } const match = /^([}\]])[ \t\n\r]*/.exec(ctx.data) if (match) { if ( match[1] === &#39;}&#39; && getType(res) !== &#39;Object&#39; || match[1] === &#39;]&#39; && getType(res) !== &#39;Array&#39; ) { throw Error(&#39;解析错误&#39;) } advance(ctx, match[0].length) return false } return true } const advance = (context: { data: string }, num: number) => { context.data = context.data.slice(num) } const parseValue = (context: { data: string }, match: any[]) => { advance(context, match[0].length) const valMatch = /^"(.*?)"$/.exec(match[1]) if (valMatch) { return valMatch[1] } if (match[1] === &#39;null&#39;) { return null } if (match[1] === &#39;true&#39;) { return true } if (match[1] === &#39;false&#39;) { return false } if (isNaN(+match[1])) { throw Error(&#39;解析错误&#39;) } return Number(match[1]) } const parseObjValue = (context: { data: string }) => { const match = /^[ \n\t\r]*((".*?")|([0-9A-Za-z]*))[ \t\n\r]*/.exec(context.data) if (match) { return parseValue(context, match) } new Error(&#39;解析错误&#39;) } const parseArrValue = (context: { data: string }) => { const refMatch = /^({|\[[ \n\t\r]*)/.exec(context.data) if (refMatch) { return parseData(context) } const match = /^((".*?")|([0-9a-zA-Z]*))[ \n\t\r]*[,]?[ \n\t\r]*/.exec(context.data) if (match) { return parseValue(context, match) } throw Error(&#39;解析错误&#39;) } const parseData = (ctx: { data: string }) => { let res: any = &#39;&#39; let currentState = State.INIT while (isEnd(ctx, res)) { switch (currentState) { case State.INIT: { const match = /^[ \t\n\r]*/.exec(ctx.data) if (match?.[0].length) { advance(ctx, match[0].length) } if (ctx.data[0] === &#39;{&#39;) { res = {} currentState = State.OBJECTSTART } else if (ctx.data[0] === &#39;[&#39;) { res = [] currentState = State.ARRAYSTART } else { res = parseObjValue(ctx) } } break case State.OBJECTSTART: { const match = /^{[ \t\n\r]*/.exec(ctx.data) if (match) { advance(ctx, match[0].length) currentState = State.OBJVALSTART } } break case State.OBJVALSTART: { const match = /^"(.*?)"[ \n\t\r]*:[ \n\t\r]*/.exec(ctx.data) if (match) { advance(ctx, match[0].length) if (ctx.data[0] === &#39;{&#39; || ctx.data[0] === &#39;[&#39;) { res[match[1]] = parseData(ctx) } else { res[match[1]] = parseObjValue(ctx) } currentState = State.OBJVALEND } } break case State.OBJVALEND: { const match = /^[ \t\n\r]*(,)[ \t\n\r]*/.exec(ctx.data) if (match) { if (match[1] === &#39;,&#39;) { currentState = State.OBJVALSTART } advance(ctx, match[0].length) } } break case State.ARRAYSTART: { const match = /^\[[ \t\n\r]*/.exec(ctx.data) if (match) { advance(ctx, match[0].length) currentState = State.ARRVALSTART } } break case State.ARRVALSTART: res.push(parseArrValue(ctx)) break // no default } } return res } export const parse = (data: string | number | null | boolean) => { if (typeof data === &#39;number&#39; || data === null || typeof data === &#39;boolean&#39;) { return data } const context = { data } return parseData(context) }
以上就是关于“JSON.stringify与JSON.parse怎么实现”这篇文章的内容,相信大家都有了一定的了解,希望小编分享的内容对大家有帮助,若想了解更多相关的知识内容,请关注编程笔记行业资讯频道。