1function jsonStringify (data) {2 // 检查对象是否有循环引用3 const isCyclic = (obj) => {4 // 使用Set数据类型存储检测到的对象5 const stackSet = new Set()6 let detected = false7
8 const detect = (obj) => {9 // 如果它不是对象类型,可以直接跳过它10 if (obj && typeof obj !== 'object') {107 collapsed lines
11 return12 }13
14 // 当要检查的对象在stackSet中已经存在时,这意味着存在循环引用15 if (stackSet.has(obj)) {16 return (detected = true)17 }18 // 将当前 obj 保存在Set19 stackSet.add(obj)20
21 for (const key in obj) {22 if (Object.prototype.hasOwnProperty.call(obj, key)) {23 detect(obj[key])24 }25 }26 // 级别检测完成后,请删除当前对象,以免误判27 /*28 对象的属性指向同一个引用, 如未删除,则视为循环引用29 let tempObj = {30 name: 'fatfish'31 }32 let obj4 = {33 obj1: tempObj,34 obj2: tempObj35 }36 */37 stackSet.delete(obj)38 }39
40 detect(obj)41
42 return detected43 }44
45 // 在包含循环引用的对象上执行此方法将引发错误。46 if (isCyclic(data)) {47 throw new TypeError('Converting circular structure to JSON')48 }49
50 // 在尝试转换BigInt类型的值时会抛出一个错误51 if (typeof data === 'bigint') {52 throw new TypeError('Do not know how to serialize a BigInt')53 }54
55 const type = typeof data56 const commonKeys1 = ['undefined', 'function', 'symbol']57 const getType = (s) => {58 return Object.prototype.toString.call(s).replace(/\[object (.*?)\]/, '$1').toLowerCase()59 }60
61 // not an object62 if (type !== 'object' || data === null) {63 let result = data64
65 // 数字Infinity和NaN,以及值null,都被认为是null。66 if ([NaN, Infinity, null].includes(data)) {67 result = 'null'68 // undefined、Function和Symbol不是有效的JSON值。69 // 如果在转换过程中遇到任何这样的值,它们要么被省略(当在对象中找到时),要么被更改为null(当在数组中找到时).70 // 当传入像JSON.stringify(function(){})或JSON.stringify(undefined)这样的“纯”值时,JSON.stringify()可以返回undefined。71 } else if (commonKeys1.includes(type)) {72 return undefined73 } else if (type === 'string') {74 result = '"' + data + '"'75 }76
77 return String(result)78 } else if (type === 'object') {79 // 如果值具有toJSON()方法,则它负责定义将序列化的数据。80 // Date的实例通过返回一个字符串(与Date . toisostring()相同)来实现toJSON()函数。81 // 因此,它们被视为字符串。82 if (typeof data.toJSON === 'function') {83 return jsonstringify(data.toJSON())84 } else if (Array.isArray(data)) {85 const result = data.map((it) => {86 // 如果在转换过程中遇到任何这样的值,它们要么被省略(当在对象中找到时),要么被更改为null(当在数组中找到时)87 return commonKeys1.includes(typeof it) ? 'null' : jsonstringify(it)88 })89
90 return `[${result}]`.replace(/'/g, '"')91 } else {92 // Boolean、Number和String对象在字符串化过程中按照传统的转换语义转换为相应的基元值。93 if (['boolean', 'number'].includes(getType(data))) {94 return String(data)95 } else if (getType(data) === 'string') {96 return '"' + data + '"'97 } else {98 const result = []99
100 // 所有其他Object实例(包括Map、Set、WeakMap和WeakSet)将只序列化它们的可枚举属性。101 Object.keys(data).forEach((key) => {102 // 所有以符号为键的属性将被完全忽略,即使在使用替换函数时也是如此。103 if (typeof key !== 'symbol') {104 const value = data[key]105
106 // undefined、Function和Symbol不是有效的JSON值。107 if (!commonKeys1.includes(typeof value)) {108 result.push(`"${key}":${jsonstringify(value)}`)109 }110 }111 })112
113 return `{${result}}`.replace(/'/, '"')114 }115 }116 }117}