JavaScript原型链是对象通过__proto__直接链接另一对象并沿链委托查找属性和方法的机制,不复制、无父类声明,仅有一条动态可变的查找路径。

JavaScript 原型链不是“模拟继承”,而是**对象直接通过 __proto__ 链接另一个对象,查找属性和方法时沿链向上委托**。它不复制,不声明“父类”,只有一条动态可变的查找路径。
原型链怎么形成:从 __proto__ 和 prototype 的关系说起
每个函数(包括构造函数)都有一个 prototype 属性,指向一个对象;每个由该函数创建的实例,其内部 __proto__ 会自动指向该函数的 prototype。这就是链的起点。
关键点:
-
__proto__是实例身上的内部引用(非标准但普遍支持),prototype是函数才有的显式属性 -
Object.prototype.__proto__是null,这是原型链终点 -
Function.prototype.__proto__ === Object.prototype,说明函数也是对象
function Animal(name) {
this.name = name;
}
Animal.prototype.speak = function() {
console.log(this.name + ' makes a sound');
};
const dog = new Animal('Dog');
console.log(dog.__proto__ === Animal.prototype); // true
console.log(Animal.prototype.__proto__ === Object.prototype); // true
console.log(Object.prototype.__proto__); // null
继承如何发生:属性查找就是原型链遍历
当你访问 dog.speak(),JS 引擎按顺序检查:dog 自身 → dog.__proto__(即 Animal.prototype)→ Animal.prototype.__proto__(即 Object.prototype)→ 最终到 null。找到第一个匹配就停止。
常见误解与陷阱:
- 修改
Animal.prototype会影响所有已有和未来的Animal实例(因为共用同一对象) - 给
dog.speak = ...会遮蔽原型上的同名方法,后续调用走实例自身,不触发委托 - 箭头函数没有
prototype,不能用作构造函数,也不参与原型链构建
实现“子类”继承:手动设置 __proto__ 或用 Object.setPrototypeOf()
ES6 class 是语法糖,底层仍靠原型链。手动模拟继承时,关键是让子构造函数的原型对象的 __proto__ 指向父构造函数的原型对象。
function Animal(name) { this.name = name; }
Animal.prototype.eat = function() { console.log('eating'); };
function Dog(name, breed) {
Animal.call(this, name); // 继承实例属性
this.breed = breed;
}
// 关键一步:建立原型链
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog; // 修复 constructor 指向
Dog.prototype.bark = function() { console.log('Woof!'); };
const myDog = new Dog('Max', 'Golden');
myDog.eat(); // ✅ 来自 Animal.prototype
myDog.bark(); // ✅ 来自 Dog.prototype
注意:Object.create(Animal.prototype) 比直接赋值 Dog.prototype = Animal.prototype 安全,后者会让子类修改影响父类原型。
现代写法里原型链还在吗:class、extends 和 super 的本质
是的,完全依赖原型链。extends 会自动设置子类 prototype.__proto__ 指向父类 prototype,并确保子类 constructor 正确继承父类静态方法(通过 SubClass.__proto__ === SuperClass)。
容易忽略的细节:
-
super()在子类构造器中必须调用,否则无法初始化this—— 这是因为子类构造器默认不绑定this,需由父类构造器完成 -
static方法不进入原型链,它们存在于构造函数自身上,通过__proto__链继承(如Dog.__proto__ === Animal) -
instanceof判断基于原型链:检查右操作数的prototype是否在左操作数的原型链上
原型链机制本身简单,但组合 new、call、Object.create、class 后,哪一层该改什么、谁引用谁,稍不注意就会断链或污染共享原型。调试时优先查 obj.__proto__ 和 Constructor.prototype 是否对得上,比看代码逻辑更快定位问题。











