手写 JSON.stringify / parse
手写 JSON.stringify
要点(也是面试爱问的边界):
undefined、函数、Symbol:作为对象值会被忽略,作为数组项变成null,作为顶层值返回undefinedNaN、Infinity、null都序列化为"null"- 对象若有
toJSON方法,序列化其返回值(如Date) - 不处理循环引用(原生会抛错)
function jsonStringify(data) {
const type = typeof data;
if (data === null) return "null";
if (type === "number") {
return Number.isFinite(data) ? String(data) : "null"; // NaN/Infinity -> null
}
if (type === "boolean") return String(data);
if (type === "string") return `"${data}"`;
// 顶层的 undefined / function / symbol 返回 undefined
if (type === "undefined" || type === "function" || type === "symbol") {
return undefined;
}
if (type === "object") {
// Date 等带 toJSON 的对象
if (typeof data.toJSON === "function") return jsonStringify(data.toJSON());
if (Array.isArray(data)) {
const items = data.map((item) => {
const v = jsonStringify(item);
return v === undefined ? "null" : v; // 数组里的 undefined/function -> null
});
return `[${items.join(",")}]`;
}
// 普通对象:忽略值为 undefined/function/symbol 的键
const items = [];
for (const key in data) {
if (Object.prototype.hasOwnProperty.call(data, key)) {
const v = jsonStringify(data[key]);
if (v !== undefined) items.push(`"${key}":${v}`);
}
}
return `{${items.join(",")}}`;
}
}
jsonStringify({ a: 1, b: undefined, c: [1, undefined, () => {}], d: null });
// => {"a":1,"c":[1,null,null],"d":null}
手写 JSON.parse
最简单的方式是借助 new Function(生产环境有 XSS 风险,仅作演示):
function jsonParse(str) {
return new Function("return " + str)();
}
严谨实现需要写一个递归下降解析器(词法分析 + 语法分析),逐字符扫描处理
{}/[]/字符串/数字/字面量。面试中能说清「为什么不能直接eval」「如何做状态机解析」即可。