目录

一、序列化与反序列化:JavaScript 对象的“变形记”

1.1 概念与核心价值

1.2 核心 API:JSON.stringify() 与 JSON.parse()

1.2.1 序列化:JSON.stringify()

1.2.2 反序列化:JSON.parse()

1.3 实战场景与注意事项

典型应用场景:

常见陷阱:

二、原型与原型链:JavaScript 对象的“继承基因”

2.1 原型(Prototype):对象的“共享衣橱”

核心关联关系:

2.2 原型链(Prototype Chain):属性查找的“瀑布流”

原型链的终点与内置原型:

2.3 原型链的实际应用

1. 实现继承(ES6 class 语法糖的底层机制):

2. 扩展内置对象功能(谨慎使用):

3. 理解 instanceof 运算符:

三、总结:从数据到对象的 JavaScript 世界观


JavaScript 作为前端开发的基石,其独特的数据处理机制和对象模型是构建复杂应用的基础。本文将深入探讨两个核心概念:序列化与反序列化(数据持久化与传输的核心)和原型与原型链(对象继承与共享的底层机制),帮助开发者夯实基础,提升代码设计能力。

一、序列化与反序列化:JavaScript 对象的“变形记”

1.1 概念与核心价值

序列化(Serialization)是将 JavaScript 对象转换为可传输/存储的字符串格式的过程;反序列化(Deserialization)则是其逆过程,将字符串还原为对象。二者共同解决了数据持久化(如本地存储)和跨上下文传输(如网络请求)的核心问题。

1.2 核心 API:JSON.stringify()JSON.parse()

1.2.1 序列化:JSON.stringify()

将对象转换为 JSON 字符串,支持三个参数:

  • value:待序列化的对象
  • replacer:自定义过滤/转换函数(可选)
  • space:格式化缩进空格数(可选,美化输出)

基础用法

const user = { 
name: "John", 
age: 30, 
roles: ["admin", "editor"],
birthDate: new Date("1995-01-01")
};
const jsonStr = JSON.stringify(user); 
// 输出:{"name":"John","age":30,"roles":["admin","editor"],"birthDate":"1995-01-01T00:00:00.000Z"}

高级技巧

  • 过滤敏感字段:通过 replacer 函数排除密码等信息
    JSON.stringify(user, (key, value) => {
    if (key === "password") return undefined; // 过滤密码
    return value;
    });
  • 处理特殊类型:Date 对象会自动转为 ISO 字符串,但函数、undefined、Symbol 会被忽略
  • 循环引用处理:需自定义检测(如使用 WeakSet 缓存已处理对象)
    const obj = { name: "Parent" };
    obj.child = { parent: obj }; // 循环引用
    const cache = new WeakSet();
    JSON.stringify(obj, (key, value) => {
    if (typeof value === "object" && value !== null) {
    if (cache.has(value)) return "[Circular]";
    cache.add(value);
    }
    return value;
    });
    // 输出:{"name":"Parent","child":{"parent":"[Circular]"}}
1.2.2 反序列化:JSON.parse()

将 JSON 字符串还原为对象,支持两个参数:

  • text:JSON 字符串
  • reviver:自定义还原函数(可选,用于恢复特殊类型)

基础用法

const parsedUser = JSON.parse(jsonStr);
console.log(parsedUser.roles[0]); // 输出:"admin"

高级技巧

  • 恢复 Date 类型:通过 reviver 函数将字符串转为 Date 对象
    const data = JSON.parse('{"date":"2025-05-10T12:00:00.000Z"}', (k, v) => {
    if (k === "date") return new Date(v);
    return v;
    });
    console.log(data.date instanceof Date); // 输出:true
  • 安全解析:避免使用 eval('(' + jsonStr + ')')(存在 XSS 风险),优先使用 JSON.parse()

1.3 实战场景与注意事项

典型应用场景:
  1. 网络传输:API 请求/响应中 JSON 数据的编码与解码
  2. 本地存储localStorage/sessionStorage 仅支持字符串存储,需序列化对象
    // 存储
    localStorage.setItem("user", JSON.stringify(user));
    // 读取
    const savedUser = JSON.parse(localStorage.getItem("user"));
  3. 跨页面通信:通过 postMessage 传递对象时需先序列化
常见陷阱:
  • 数据类型丢失:函数、undefined、Symbol 会被序列化忽略
  • 循环引用报错:直接序列化循环引用对象会抛出 TypeError
  • 二进制数据处理:需手动转为 Base64 字符串(如 ArrayBuffer → Base64)

二、原型与原型链:JavaScript 对象的“继承基因”

2.1 原型(Prototype):对象的“共享衣橱”

每个 JavaScript 对象(除 null 外)都有一个原型对象,通过 [[Prototype]] 内部属性关联(可通过 Object.getPrototypeOf(obj)obj.__proto__ 访问)。原型对象的属性和方法会被所有关联对象共享继承

核心关联关系:
  • 构造函数的 prototype 属性:指向实例对象的原型
  • 实例对象的 __proto__ 属性:指向构造函数的 prototype
  • 原型对象的 constructor 属性:指回关联的构造函数

代码示例

function Person(name) {
this.name = name; // 实例属性
}
// 原型方法(所有实例共享)
Person.prototype.sayHello = function() {
console.log(`Hello, I'm ${this.name}`);
};


const person = new Person("Alice");
console.log(person.__proto__ === Person.prototype); // true(实例→原型)
console.log(Person.prototype.constructor === Person); // true(原型→构造函数)

2.2 原型链(Prototype Chain):属性查找的“瀑布流”

当访问对象的属性时,JavaScript 会先在对象自身查找;若不存在,则沿 __proto__ 链向上查找原型对象,直至找到或抵达链的终点(Object.prototype.__proto__ === null)。这条查找链即原型链

原型链的终点与内置原型:
  • 顶层原型Object.prototype(所有对象的“根原型”)
  • 内置对象原型Array.prototypeString.prototype 等,提供内置方法(如 array.push() 继承自 Array.prototype

属性查找示例

const arr = [1, 2, 3];
arr.push(4); // 自身无 push → 查找 Array.prototype.push → 找到并执行
arr.toString(); // Array.prototype 无 toString → 查找 Object.prototype.toString → 找到并执行

2.3 原型链的实际应用

1. 实现继承(ES6 class 语法糖的底层机制):
// 父类
function Animal(name) {
this.name = name;
}
Animal.prototype.eat = function() {
console.log(`${this.name} is eating`);
};


// 子类
function Dog(name, breed) {
Animal.call(this, name); // 继承实例属性
this.breed = breed;
}
// 继承原型方法(核心)
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog; // 修复 constructor 指向


const dog = new Dog("Buddy", "Golden Retriever");
dog.eat(); // 输出:"Buddy is eating"(继承自 Animal.prototype)
2. 扩展内置对象功能(谨慎使用):
// 为数组添加去重方法(不推荐直接修改内置原型,可能引发冲突)
Array.prototype.unique = function() {
return [...new Set(this)];
};
[1, 2, 2, 3].unique(); // [1, 2, 3]
3. 理解 instanceof 运算符

判断对象是否在构造函数的原型链上:

dog instanceof Dog; // true(dog → Dog.prototype → Animal.prototype → Object.prototype)
dog instanceof Animal; // true(原型链包含 Animal.prototype)

三、总结:从数据到对象的 JavaScript 世界观

  • 序列化与反序列化解决了数据的“跨时空旅行”问题,是前后端通信、本地存储的基础,掌握 JSON.stringify/JSON.parse 的高级用法可应对复杂场景(如循环引用、类型恢复)。

  • 原型与原型链是 JavaScript 面向对象的核心,理解其机制能帮助开发者写出更高效的代码(如共享方法减少内存占用),并深入掌握继承、this 指向等底层逻辑。

这两个概念虽看似独立,却共同构成了 JavaScript 处理数据与对象的基石。无论是构建大型应用还是调试复杂问题,扎实的基础都是提升开发效率的关键。

推荐延伸学习:ES6+ 中的 class 语法糖与原型链的关系、WeakMap 解决循环引用序列化问题、Object.setPrototypeOf() 与原型链动态修改。

更多推荐