属性继承是通过__proto__构成的查找路径实现的:实例→构造函数.prototype→Object.prototype→null,物理路径决定属性访问,而非constructor或instanceof等逻辑标识。
属性继承不是“复制”或“绑定”,而是一条可追踪的查找路径——从实例出发,逐级向上访问 __proto__ 指向的对象,直到找到目标属性,或抵达 null。这条路径就是继承发生的物理现场。
原型链的起点:每个实例都有一个 __proto__
当你用 new Cat() 创建实例时,JavaScript 会自动为该实例设置一个内部链接 [[Prototype]](在绝大多数环境中暴露为 __proto__)。这个链接不是凭空产生,而是严格指向构造函数的 Cat.prototype 对象。
-
cat.__proto__ === Cat.prototype—— 恒成立 -
cat.hasOwnProperty('username')返回true,说明该属性在实例自身上 -
cat.hasOwnProperty('behavior')返回false,说明它不在实例上,需继续往上找
向上跳转:prototype 是函数才有的,__proto__ 是对象才有的
函数(如 Cat、Dog)有 prototype 属性,它是一个普通对象;而所有对象(包括 Cat.prototype)都有 __proto__,指向它的原型。
-
Cat.prototype.__proto__ === Object.prototype—— 因为Cat.prototype是普通对象,由Object构造 -
Object.prototype.__proto__ === null—— 原型链终点,不可再查 - 所以完整路径是:
cat → Cat.prototype → Object.prototype → null
多层继承时的物理路径可视化
当执行 Dog.prototype = new Cat() 后,dog 实例的查找路径就变长了:
-
dog.__proto__→ 指向new Cat()实例(即dog的直接原型) - 该
Cat实例的__proto__→ 指向Cat.prototype -
Cat.prototype.__proto__→ 指向Object.prototype - 最终路径:
dog → cat实例 → Cat.prototype → Object.prototype → null
调用 dog.behavior() 时,引擎就按此顺序逐层检查,直到在 Cat.prototype 上命中方法。
为什么不能只靠 constructor 或 instanceof 判断继承?
它们反映的是逻辑关系,不是物理路径:
-
dog.constructor可能被覆盖,不一定指向Dog -
dog instanceof Cat为true,是因为Cat.prototype出现在dog的原型链中 —— 这个判断本身依赖的就是那条物理路径 - 真正起作用的,永远是
__proto__链上的实际引用,而非名字或标签










