原型链的本质是对象的__proto__指向其构造函数的prototype,通过[[Prototype]]内部属性实现属性查找委托,终点为null,Object.create()可手动构建,属性赋值不触发委托。

原型链的本质是对象的 __proto__ 指向其构造函数的 prototype
JavaScript 中没有类继承,只有对象间委托——原型链就是这条委托链。每个对象都有一个内部属性 [[Prototype]](可通过 __proto__ 访问),它指向创建该对象的构造函数的 prototype 对象。当访问一个对象上不存在的属性时,JS 引擎会顺着 __proto__ 一层层向上查找,直到找到或抵达 null。
常见错误现象:
• 直接修改实例对象的 __proto__ 导致意外覆盖原型行为
• 误以为 Object.prototype.__proto__ === null 是特例,其实所有原型链终点都是 null
• 在 ES6 class 中误用 super() 前访问 this,本质是没理解 class 只是语法糖,底层仍依赖原型链初始化
用 Object.create() 手动构建原型链最直观
这是理解原型继承最干净的方式,绕过构造函数和 new 的干扰,直击委托关系。
-
Object.create(proto)创建一个新对象,其__proto__直接设为proto - 若想让子对象继承父对象的方法,就把父对象传给
Object.create() - 注意:
Object.create(null)创建的是“无原型”对象,查不到toString等内置方法
示例:
立即学习“Java免费学习笔记(深入)”;
const animal = { eats: true };
const cat = Object.create(animal);
cat.meows = true;
console.log(cat.eats); // true —— 从 animal 委托获得
构造函数 + prototype 是最常见的继承实现方式
虽然 ES6 后多用 class,但底层仍是这套机制。关键点在于:必须让子构造函数的 prototype 关联到父构造函数的实例(或至少是其原型),才能形成有效委托链。
- 错误写法:
Child.prototype = Parent.prototype—— 这会让子类直接污染父类原型 - 正确写法:
Child.prototype = Object.create(Parent.prototype),再补上constructor指回Child - 必须在重写
prototype后、添加实例方法前执行,否则新方法会丢失 - 调用父构造函数需显式用
Parent.call(this, ...),否则实例属性不会被初始化
ES6 class 和 extends 并未改变原型链逻辑
它只是把上述手动操作封装成更易读的语法,但运行时行为完全一致。编译后仍是设置 __proto__ 和 prototype 的关系。
-
class B extends A会自动设置B.__proto__ === A(静态继承)和B.prototype.__proto__ === A.prototype(实例继承) -
super()在子类构造器中必须调用,否则无法初始化this,本质是确保父构造函数被执行 - 箭头函数没有自己的
prototype,不能用作构造函数,也无法参与原型链继承
容易忽略的一点:原型链只对**属性读取**生效;属性赋值永远发生在当前对象自身,不会触发向上委托。这也是为什么 obj.prop = value 不会修改原型上的同名属性。











