一、为什么JSON面试题如此重要?
在现代Web开发中,JSON(JavaScript Object Notation)已成为前后端数据交换的事实标准。无论是RESTful API、WebSocket通信,还是本地存储(localStorage),JSON都扮演着核心角色。因此,在各类前端、全栈开发的JSON面试题中,考察开发者对JSON的理解程度是必经环节。
许多候选人往往忽视了JSON背后的细节,例如:为什么不能直接解析带有函数定义的字符串?JSON.stringify如何处理循环引用?如何进行高效的JSON深拷贝?本文将逐一解答这些在JSON面试题中高频出现的问题。
二、JSON基础语法与常见误区
在深入算法之前,我们需要明确JSON的数据类型限制。这是所有JSON面试题的基础。
支持的类型
对象(Object)、数组(Array)、字符串(String)、数字(Number)、布尔值(Boolean)、null。
不支持的类型
函数(Function)、日期(Date)、undefined、Symbol、RegExp等。这些类型在序列化时会被忽略或转换。
键名限制
JSON对象的所有键名必须使用双引号包裹,这是与JavaScript对象字面量最大的区别之一。
示例:非法的JSON字符串
// 错误示例:单引号、无引号键名、尾随逗号
{
'name': 'John', // 错误:必须使用双引号
age: 25, // 错误:键名必须加双引号
hobby: 'coding', // 错误:键名必须加双引号
tags: ['JS', 'HTML'],
}
正确的JSON格式应为:
{
"name": "John",
"age": 25,
"hobby": "coding",
"tags": ["JS", "HTML"]
}
三、JSON核心方法:Parse与Stringify
JSON.parse()和JSON.stringify()是处理JSON数据的两个核心API。在JSON面试题中,面试官通常会考察它们的参数用法及返回值差异。
1. JSON.parse():从字符串解析为对象
该方法接收两个参数:要解析的字符串和一个可选的replacer函数(用于过滤或转换属性)。
const jsonString = '{"name": "Alice", "age": 30}';
const obj = JSON.parse(jsonString);
console.log(obj.name); // "Alice"
2. JSON.stringify():从对象序列化为字符串
该方法接收三个参数:要序列化的对象、可选的replacer函数或数组、可选的缩进字符。
Replacer函数的使用
Replacer函数在序列化过程中会被调用,用于过滤或转换值。如果返回undefined,该属性将被忽略。
const data = { name: "Bob", age: 25, secret: "123" };
const json = JSON.stringify(data, (key, value) => {
if (key === "secret") return undefined; // 隐藏敏感信息
return value;
}, 2);
console.log(json);
/
{
"name": "Bob",
"age": 25
}
/
Space缩进格式化
第三个参数用于美化输出,通常用于调试或生成可读性强的配置文件。
const obj = { a: 1, b: 2 };
console.log(JSON.stringify(obj, null, 4));
/
{
"a": 1,
"b": 2
}
/
toJSON方法控制序列化
如果对象定义了toJSON方法,JSON.stringify会调用它并序列化其返回值。
const date = new Date();
const json = JSON.stringify({
date: {
toJSON: function() {
return this.toISOString();
}
}
});
// 输出: {"date":"2023-10-01T00:00:00.000Z"}
四、JSON深拷贝:原理与局限
在JavaScript中,对象是引用类型。简单的赋值操作只会复制引用,导致修改原对象会影响新对象。因此,深拷贝成为JSON面试题中的常客。利用JSON.stringify实现深拷贝是一种常见但存在局限性的方法。
1. 基于JSON的深拷贝实现
function deepClone(obj) {
if (obj === null) return null;
if (typeof obj !== 'object') return obj;
try {
return JSON.parse(JSON.stringify(obj));
} catch (e) {
console.error('Deep clone failed due to circular reference or non-JSON types');
return null;
}
}
2. 局限性分析
| 数据类型 | 序列化结果 | 原因 |
|---|---|---|
| Function | 被忽略 | JSON不支持函数 |
| undefined | 被忽略 | JSON不支持undefined |
| Symbol | 被忽略 | JSON不支持Symbol |
| RegExp | {} | 正则对象序列化为空对象 |
| Date | 字符串 | 转换为ISO字符串,反序列化后变为字符串而非Date对象 |
| Circular Reference | Error | 循环引用导致栈溢出 |
3. 处理循环引用的深拷贝
当对象存在循环引用时,上述方法会失败。在高级JSON面试题中,面试官可能要求实现一个能处理循环引用的深拷贝函数。
function deepCloneWithCycle(obj, map = new WeakMap()) {
if (obj === null || typeof obj !== 'object') return obj;
if (map.has(obj)) return map.get(obj);
const clone = Array.isArray(obj) ? [] : {};
map.set(obj, clone);
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
clone[key] = deepCloneWithCycle(obj[key], map);
}
}
return clone;
}
五、JSON安全漏洞与常见陷阱
在处理用户输入的JSON数据时,安全性至关重要。以下是在实际开发和JSON面试题中常被提及的安全问题。
1. JSON Hijacking
虽然现代浏览器已修复此漏洞,但在旧版IE中,攻击者可以通过覆盖Array构造函数,在页面加载时窃取JSON数据。防御方法包括:
- ● 始终使用JSON.parse()而非eval()
- ● 设置正确的Content-Type为application/json
- ● 在响应头部添加X-Content-Type-Options: nosniff
2. 数值精度问题
JavaScript中的Number类型遵循IEEE 754双精度标准,对于超过17位的整数可能会丢失精度。在JSON传输大额数据(如金额、ID)时,建议使用字符串类型。
// 精度丢失示例
console.log(1234567890123456789); // 1234567890123456800
const json = '{"id": "1234567890123456789"}'; // 推荐:使用字符串
3. 大整数的序列化
当使用JSON.stringify序列化包含大整数的对象时,如果整数超过2^53-1,可能会发生精度丢失。建议在序列化前将大整数转换为字符串。
六、JSON面试题高频考点汇总
以下是近年来前端面试中关于JSON的高频问题及其解答思路。
JSON是一种数据格式,仅支持对象、数组、字符串、数字、布尔和null。而JavaScript对象是语言层面的数据结构,支持函数、日期、正则等。JSON必须是双引号,JS对象键名可省略引号。
简单场景可使用JSON.parse(JSON.stringify(obj))。复杂场景需使用递归,处理循环引用(使用WeakMap)、特殊类型(Date、RegExp、Function)及原型链。
第二个参数是replacer函数,用于在解析过程中过滤或转换属性。它在值被返回前被调用,可以修改最终的对象结构。
第三个参数是space,用于在序列化结果中添加空白符,使输出更易读。可以是数字(最多10)或字符串。
在序列化时,如果遇到循环引用,JSON.stringify会抛出错误。需要手动检测循环引用,或使用第三方库如lodash的_.cloneDeep。
七、总结
掌握JSON不仅是通过JSON面试题的关键,更是前端开发者日常工作的必备技能。从基础的序列化与反序列化,到复杂的深拷贝与循环引用处理,再到安全与性能优化,每一个环节都蕴含着丰富的知识点。建议开发者在面试前,结合本文提供的代码示例,亲手实现一遍深拷贝函数,并深入理解JSON.parse和JSON.stringify的内部机制,以便在面试中游刃有余。
希望本文能帮助您全面理解JSON面试题的相关知识点,祝您面试成功!