利用原生 js 模拟出 JSON.parse 和 JSON.stringify
最近利用原生 javascript 模仿出原生的 JSON.parse 和 JSON.stringify 的效果
(function (win) {
const MOCK_JSON = {
// 记录结构体的数量(结构体是指字符串格式的[]和{})
structure_len: 0,
// 记录结构体的结构对象
map_data: {},
structure_key: '$',
init() {
this.structure_len = 0
this.map_data = {}
this.structure_key = '$'
},
parse(str) {
this.init()
// this.inspectionFormat()
let reg = /\\/g
if (reg.test(str)) {
if (str[0] == '"') {
str = str.slice(1, str.length - 1)
}
return str.replace(reg, '')
}
str = str.replace(/\[ /g, '[')
str = str.replace(/\s,/g, ',')
str = str.replace(/,\s/g, ',')
str = str.replace(/\s:/g, ':')
str = str.replace(/:\s/g, ':')
// 处理结构体 key
let $arr = str.match(/\$+/g)
let $len = $arr[0].length
for (let i = 1; i < $arr.length; i++) {
if ($len < $arr[i].length) {
$len = $arr[i].length
}
}
let $key = this.structure_key
for (let i = 0; i < $len; i++) {
this.structure_key += $key
}
return this.handleData(str, 0)
},
inspectionFormat(obj) {
let regObject = /{"?.+[^"]:.+}|{[^"].+"?:.+}|{[^"]|{":|{".*"}|{".*":.{0}}|{".*"[^:].{0}}|,}| "/g
let regArray = /\[,.*|.*,\]/g
if (regObject.test(obj)) {
throw new Error('{} 数组格式有误')
}
if (regArray.test(obj)) {
throw new Error('[] 数组格式有误')
}
},
changeData(data) {
--this.structure_len
if (this.callType(data) == 'array') {
let array = []
let len = data.length
for (let i = 0; i < len; i++) {
let elem = data[i]
if (this.callType(elem) == 'string' && elem.indexOf(this.structure_key) > -1) {
array.push(this.changeData(this.map_data[elem]))
} else {
array.push(this.handleValue(elem))
}
}
if (!this.structure_len) {
this.init()
}
return array
} else if (this.callType(data) == 'object') {
let object = {}
for (let attr in data) {
let value = data[attr]
if (this.callType(value) == 'string' && value.indexOf(this.structure_key) > -1) {
object[attr] = this.changeData(this.map_data[value])
} else {
object[attr] = value
}
}
if (!this.structure_len) {
this.init()
}
return object
}
},
handleData(obj, idx) {
let left_brace = obj.lastIndexOf('{'),
right_brace = obj.slice(left_brace).indexOf('}'),
left_bracket = obj.lastIndexOf('['),
right_bracket = obj.slice(left_bracket).indexOf(']')
if (left_brace == -1 && left_bracket == -1) {
return this.changeData(this.map_data[this.structure_key + (this.structure_len - 1)])
}
// 最小结构体为 {}
if (left_brace > left_bracket) {
this.map_data[`${this.structure_key}${idx}`] = this.handleObject(obj.slice(left_brace, left_brace + right_brace + 1))
++this.structure_len
let left_surplus = obj.slice(0, left_brace)
let right_surplus = obj.slice(left_brace + right_brace + 1)
return this.handleData(`${left_surplus}${this.structure_key}${idx}${right_surplus}`, ++idx)
} else if (left_brace < left_bracket) {
// 最小结构体为 []
this.map_data[`${this.structure_key}${idx}`] = this.handleArray(obj.slice(left_bracket, left_bracket + right_bracket + 1))
++this.structure_len
let left_surplus = obj.slice(0, left_bracket)
let right_surplus = obj.slice(left_bracket + right_bracket + 1)
return this.handleData(`${left_surplus}${this.structure_key}${idx}${right_surplus}`, ++idx)
} else {
// 最外层为 {}
if (obj[0] == '{') {
this.map_data[`${this.structure_key}${idx}`] = this.handleObject(obj)
++this.structure_len
}
// 最外层为 []
if (obj[0] == '[') {
this.map_data[`${this.structure_key}${idx}`] = this.handleArray(obj)
++this.structure_len
}
}
},
// 对象字符串格式化为对象
handleObject(obj) {
let newObj = {}
// 空对象
if (obj.length == 2) {
return newObj
}
// 检查对象格式
let regObject = /{"?.+[^"]:.+}|{[^"].+"?:.+}|{[^"]|{":|{".*"[^:]}|{".*":.{0}}|{".*"[^:].{0}}|,}/g
if (regObject.test(obj)) {
throw new Error(obj + ' 对象结构有误')
}
// 去除对象左右{}符号
obj = obj.slice(1, obj.length - 1)
// 先根据逗号分割
let obj_arr = obj.split(',')
obj_arr.forEach((elem) => {
// 再根据冒号分割 key 和 value
let obj_data = elem.split(':')
for (let o = 0; o < obj_data.length; o++) {
let key = this.handleKey(obj_data[o])
let value = this.handleValue(obj_data[++o])
newObj[key] = value
}
})
return newObj
},
// 数组字符串格式化为数组
handleArray(arr) {
let newArr = []
// 空数组
if (arr.length == 2) {
return newArr
}
// 检查数组格式
let reg = /\[,.*|.*,\]/g
if (reg.test(arr)) {
throw new Error(arr + ' 数组格式有误')
}
return arr.slice(1, arr.length - 1).split(',').map((elem) => this.handleValue(elem))
},
handleKey(key) {
return key.replace(/"/g, '')
},
handleValue(value) {
// 空字符串
if (value.length == 0) {
return value
}
// 存储字符串长度
let str_len = 0
if (this.callType(value) == 'string') {
value = value.replace(/"/g, '')
str_len = value.length
}
// 字符串中无数字
if (isNaN(parseFloat(value))) {
return value
} else {
// 字符串中有数字(字符串数字化后是否与原先字符串一致)
let temp = '' + parseFloat(value)
// 不一致(例如:parseFloat('123abc'))
if (temp.length != str_len) {
return value
} else {
// 一致(例如:parseFloat('123'))
return parseFloat(value)
}
}
},
// 分辨类型
callType(obj) {
let map = {
'[object Object]': 'object',
'[object Array]': 'array',
'[object Number]': 'number',
'[object Null]': 'null',
'[object Boolean]': 'boolean',
'[object Symbol]': 'symbol',
'[object Undefined]': 'undefined',
'[object Function]': 'function',
'[object RegExp]': 'regexp',
'[object String]': 'string',
'[object Date]': 'date',
'[object Math]': 'math',
}
return map[Object.prototype.toString.call(obj)]
},
// json对象字符串化
stringify(obj) {
switch (this.callType(obj)) {
case 'object':
let listObj = []
for (let attr in obj) {
listObj.push(`"${attr}":${this.stringify(obj[attr])}`)
}
return `{${listObj.join(',')}}`
case 'array':
let listArr = []
obj.forEach((elem) => {
listArr.push(this.stringify(elem))
})
return `[${listArr.join(',')}]`
case 'number':
case 'null':
case 'boolean':
return String(obj)
case 'symbol':
case 'undefined':
case 'function':
case 'regExp':
return undefined
case 'string':
return `"${obj.replace(/"/g, '\\"')}"`
case 'date':
return `"${obj.toISOString()}"`
case 'math':
return `{}`
}
}
}
win.MOCK_JSON = MOCK_JSON
})(window)
代码中也有简单的注释