JavaScript原型链是基于对象的动态继承模型,通过[[Prototype]]隐式引用实现属性委托查找,class仅为语法糖,本质仍是原型链;它强调运行时对象行为共享,而非编译期类型结构。

JavaScript 的原型链是理解对象行为的核心机制,它不是“类的替代品”,而是一种基于对象的、动态的继承模型。与传统面向对象语言中的类继承相比,原型链更灵活、更轻量,但也更容易让人困惑——关键在于:原型链操作的是运行时的对象关系,而类继承(如 Java 或 C++)描述的是编译时的类型结构。
原型链的本质:对象间共享属性和方法的委托链
每个 JavaScript 对象内部都有一个隐式引用([[Prototype]]),指向它的原型对象。当访问一个属性或方法时,引擎会先在当前对象上查找;没找到,就顺着 [[Prototype]] 去原型对象上找;还没找到,就继续向上查,直到原型为 null(即到达原型链顶端)。这个逐级委托的过程就是原型链。
例如:
const animal = { eats: true };
const dog = { bark() { return "woof"; } };
Object.setPrototypeOf(dog, animal);
console.log(dog.eats); // true ← 从 animal 原型上获取
- 没有“父类”概念,只有“原型对象”;
- 原型可以随时被修改,影响所有依赖它的对象(包括已创建的);
- 函数对象默认拥有 prototype 属性(仅用于 new 调用时设置新对象的 [[Prototype]]),别和内部 [[Prototype]] 混淆。
类语法(class)只是原型链的语法糖
ES6 引入的 class 并未改变底层机制,它只是让基于原型的继承写起来更像传统类语言:
立即学习“Java免费学习笔记(深入)”;
class Animal {
constructor(name) { this.name = name; }
speak() { console.log(`${this.name} makes a sound`); }
}
class Dog extends Animal {
bark() { console.log("woof!"); }
}
这背后仍是原型链: Dog.prototype.__proto__ === Animal.prototype Animal.prototype.__proto__ === Object.prototype
- class 定义的方法自动添加到原型上(不可枚举);
- extends 实际设置子类原型的 [[Prototype]] 指向父类原型;
- 但 class 无法表达原型链的全部能力——比如给任意对象临时指定原型,或运行时切换原型。
与经典类继承的关键差异
传统类继承强调“类型定义 + 编译期检查”,而原型链强调“对象行为 + 运行时委托”:
- 类继承中,子类“复制”或“固化”了父类的结构;原型链中,对象只是“链接”到另一个对象,共享其行为;
- 类通常不允许实例直接修改继承来的成员(除非显式重写);原型链中,任何对象都可随时增删改自己的属性,甚至覆盖原型上的同名属性;
- 多继承在类系统中复杂且受限(如 Java 单继承),而原型链天然支持“混入”(mixin):一个对象可有多个行为来源,只需把不同对象的属性复制或委托过去。
什么时候该关注原型链而非 class?
当你需要:
- 手动控制对象的原型关系(如 Object.create()、Object.setPrototypeOf());
- 实现对象组合、代理、装饰器等模式;
- 调试属性访问问题(比如为什么某个方法能调用却没定义在当前对象上);
- 理解 this 绑定、for...in 遍历范围、hasOwnProperty 判断依据等底层逻辑。
不复杂但容易忽略。










