原型链查找的逻辑边界由[[prototype]]和属性访问规则共同决定,中断于[[prototype]]为null;查找从自身开始逐级向上回溯至null,写入操作不沿原型链进行。

JavaScript 中原型链查找的逻辑边界,本质上由 对象的内部属性 [[Prototype]] 和 属性访问操作(如点号或方括号)的执行规则 共同决定;而原型链中断,则发生在查找过程无法继续向上追溯时——即当前对象的 [[Prototype]] 为 null。
原型链查找:从自身到 null 的逐级回溯
当读取一个对象的属性时,JS 引擎按如下顺序查找:
- 先在对象自身的属性中搜索(包括自有数据属性和访问器属性);
- 若未找到,且该对象的
[[Prototype]]非null,则转向其原型对象重复查找; - 持续沿
[[Prototype]]链向上,直到某一级找到该属性,或到达原型链末端([[Prototype]] === null)。
例如:let obj = {};,其 obj.__proto__ 指向 Object.prototype,而 Object.prototype.__proto__ 是 null。因此调用 obj.toString() 会查到 Object.prototype.toString;但若手动切断:Object.setPrototypeOf(obj, null),再访问 toString 就会报 TypeError(找不到该属性且链已断)。
原型链中断的两种典型场景
原型链并非总能完整延伸至 Object.prototype,以下情况会导致提前终止:
-
显式设置
[[Prototype]]为null:如Object.create(null)创建的对象,其原型就是null,无任何继承; -
构造函数未正确链接原型:比如直接赋值
F.prototype = {}后忘记补上constructor,虽不影响查找,但若后续误删了该对象的__proto__或篡改了原型链结构,也可能导致断裂; -
使用
Object.setPrototypeOf()或__proto__动态修改并设为null,会立即截断查找路径。
属性写入与原型链无关,只作用于目标对象本身
这是容易混淆的关键点:原型链仅用于读取(get)时的查找;而写入(set)操作默认只在当前对象上添加或修改属性,不会沿着原型链向上设置。
- 即使原型上有同名的可写属性,赋值仍会落在当前对象(触发“遮蔽”);
- 只有当目标属性是 setter 访问器 且未被遮蔽时,才可能触发 setter 的逻辑(此时才可能间接影响原型行为);
- 想跨原型写入,必须显式定位到原型对象,例如:
Object.getPrototypeOf(obj).prop = value。
判断原型链是否有效:不只是看 instanceof
instanceof 检查的是构造函数的 prototype 是否出现在对象的原型链中,但它不反映链是否完整或是否中途被截断。更直接的方式是:
- 用
Object.getPrototypeOf(obj)逐级检查,直到返回null; - 对比
obj.constructor.prototype与实际原型是否一致(注意:constructor可被污染); - 对关键对象做防御性判断,如
if (obj != null && typeof obj === 'object'),再进行属性访问。
不复杂但容易忽略。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











