blog
blog copied to clipboard
自己来实现JSON.stringify和JSON.parse
JSON.stringify 不能处理哪些类型
阅读资料: What you didn’t know about JSON.Stringify https://abdulapopoola.com/2017/02/27/what-you-didnt-know-about-json-stringify/
最主要的原因在于:
Because JSON is a language agnostic format JSON 是通用的文本格式和语言是无关的。如果函数定义也可以stringify的话,那就变得和语言有关了
JSON.stringify
const getType = (obj) => {
return Object.prototype.toString.call(obj).slice(8, -1).toLowerCase();
};
const getResultFromStack = (stack) => {
let result = '';
while (stack.length) {
const [key, value] = stack.shift();
const temp = (stack.length === 0) ?
`"${key}":${value}` : `"${key}":${value},`;
result += temp;
}
return `{${result}}`;
};
//『function|undefined』
const isFunctionOrUndefined = (obj) => /function|undefined/.test(getType(obj));
export default function jsonStringify(obj) {
if (obj === null)
return 'null';
if (getType(obj) === 'regexp')
return '{}';
//『字符串|布尔|数字』直接转换为string类型
if (/string|number|boolean/.test(typeof obj)) {
return (typeof obj === 'number') ? obj.toString() : `"${obj.toString()}"`;
}
//『function|undefined』 不处理
if (isFunctionOrUndefined(obj))
return '';
// 『数组』直接join 为字符串
if (Array.isArray(obj))
return `[${obj.join(',')}]`;
if (getType(obj) === 'object') {
const stack = [];
// 『对象』递归处理
for (const key in obj) {
const value = obj[key];
if (isFunctionOrUndefined(value)) {
continue;
}
stack.push([key, jsonStringify(value)]);
}
return getResultFromStack(stack);
}
}
递归处理那里,我们其实只要能把key,value 同时存放到队列里,稍后处理就可以了,使用二维数组比较方便
JSON.parse
1.最简单的实现方式, 无脑实现利用new Function
function jsonParseFunction(str) {
return new Function(`return ${str}`)();
}
2.写一个简单的针对Json的parser
思路来源于下面这篇文章,非常感谢作者: 半小时实现一个JSON 解析器 https://zhuanlan.zhihu.com/p/28049617
并且文章中解释了为什么JSON要设计成这个样子?因为它是容易解析的。读取JSON字符串的字符时,读到特定的开头,我们就能知道我们需要找的是什么值。
let str = '';
let i = 0;
const parseObject = () => {
i++;
const result = {};
while (str[i] !== '}') {
// 这个地方一开始没绕过来
const key = parseString();
i++; // 跳过冒号
const value = parseValue();
result[key] = value;
if (str[i] === ',') {
i++; // 如果是, 说明要继续往下查找
}
}
i++;
return result;
};
const parseArray = () => {
i++;
let result = [];
while (str[i] !== ']') {
result.push(parseValue());
if (str[i] === ',') {
// 跳过逗号
i++;
}
}
i++;
return result;
};
const parseString = () => {
i++;
let result = '';
while (str[i] !== '"') {
result += str[i];
i++;
}
i++;
return result;
};
const parseTrue = () => {
const content = str.substr(i, 4);
if (content === 'true') {
i += 4;
return true;
}
};
const parseFalse = () => {
const content = str.substr(i, 5);
if (content === 'false') {
i += 5;
return false;
}
};
const parseNull = () => {
const content = str.substr(i, 4);
if (content === 'null') {
i += 4;
return null;
}
};
const parseNumber = () => {
function isNumberChar(c) {
var chars = {
'-': true,
'+': true,
'e': true,
'E': true,
'.': true,
};
if (chars[c]) {
return true;
}
if (c >= '0' && c <= '9') {
return true;
}
return false;
}
let numStr = '';
while (isNumberChar(str[i])) {
numStr += str[i++];
}
return parseFloat(numStr);
};
const parseValue = () => {
switch (str[i]) {
case '{': {
return parseObject();
}
case '[': {
return parseArray();
}
case '"': {
return parseString();
}
case "t": {
return parseTrue();
}
case "f": {
return parseFalse();
}
case "n": {
return parseNull();
}
default: {
return parseNumber();
}
}
};
export default function jsonParse(orgStr) {
str = orgStr.replace(/([^"])(\s*)/g, '$1');
const result = parseValue();
console.log(result);
}
// --- 测试 ---
import jsonParse from './jsonParse';
let str = '{"a":1, "b":true, "c":false, "foo":null, "bar":[1,2,3]}';
jsonParse(str);