JS原型链查找属性本质是沿[[Prototype]]链逐级搜索原型对象,而非直接访问父构造函数;通过Object.getPrototypeOf()可手动模拟该过程,并比对原型对象确定属性来源。

JS 原型链向上追溯获取父级构造函数的属性,本质是沿着对象的 [[Prototype]] 链逐层查找,不是直接“拿到父构造函数”,而是通过原型对象间接访问其定义在 prototype 上的属性和方法。
一、核心机制:属性查找走的是 __proto__ 链,不是构造函数链
当你写 obj.someMethod(),JS 引擎做的不是“找 obj 的构造函数,再找它的 prototype”,而是:
- 先查
obj自身有没有someMethod - 没有就查
obj.__proto__(即Object.getPrototypeOf(obj)) - 还没就查
obj.__proto__.__proto__,依此类推 - 直到找到属性,或抵达
null
这个链条上的每个环节,都是某个构造函数的 prototype 对象。比如数组实例的链是:[1,2].__proto__ === Array.prototype → Array.prototype.__proto__ === Object.prototype → Object.prototype.__proto__ === null
二、怎么手动模拟向上追溯过程
可以用以下函数清晰还原 JS 引擎内部查找逻辑:
使用约定式提交(Conventional Commits)生成标准化的 Git 提交信息。适用于以下场景: (1) 暂存更改时需要提交信息; (2) 审查 diff 时希望获得结构化摘要; (3) 编写 PR 描述或变更日志(changelog)条目; (4) 用户明确要求“为本次更改编写提交信息”。 该功能会分析已暂存/未暂存的 diff,并生成按类型(type)划分范围的提交信息。
function getProperty(obj, key) {<br> let current = obj;<br> while (current !== null) {<br> if (current.hasOwnProperty(key)) return current[key];<br> current = Object.getPrototypeOf(current);<br> }<br> return undefined;<br>}
例如:getProperty([1, 2], 'map') → 返回 Array.prototype.mapgetProperty({a:1}, 'toString') → 返回 Object.prototype.toString
三、如何知道某属性来自哪个构造函数的 prototype
不能靠名字猜,得靠比对原型对象:
- 用
Object.getPrototypeOf(obj)获取当前原型 - 逐级检查它是否等于某个已知构造函数的
prototype - 例如判断
arr.map来自哪里:
const arr = [1];<br>const proto1 = Object.getPrototypeOf(arr); // Array.prototype<br>proto1 === Array.prototype // true<br>const proto2 = Object.getPrototypeOf(proto1); // Object.prototype<br>proto2 === Object.prototype // true
注意:arr.constructor 是 Array,但这个值可被改写,不具可靠性;真正稳定的是 __proto__ 指向关系。
四、常见误区提醒
-
obj.constructor.prototype不一定等于obj.__proto__(如果constructor被重写过) -
Function.prototype和Object.prototype是两条不同起点的链,但最终交汇于null - 箭头函数没有
prototype,也不能用new,所以不参与构造函数继承链 - 用
class定义的类,底层仍是函数 +prototype,extends就是自动设置子类prototype.__proto__指向父类prototype

















