在JavaScript中,每个对象都有对应的原型对象,多个对象的原型通过引用关联形成原型链,判断一个对象是否是另一个对象的原型链祖先,本质是检查前者是否出现在后者的原型链遍历路径中。下面先介绍几种常用的判断方式。

使用isPrototypeOf方法判断
isPrototypeOf是Object原型上的方法,所有对象都可以调用该方法,它接收一个对象作为参数,判断调用该方法的对象是否在参数对象的原型链上,也就是判断前者是否是后者的原型链祖先。
基本使用示例如下:
// 定义父对象
const parent = {
name: 'parent'
};
// 定义子对象,其原型指向parent
const child = Object.create(parent);
// 判断parent是否是child的原型链祖先
console.log(parent.isPrototypeOf(child)); // 输出true
// 判断child是否是parent的原型链祖先
console.log(child.isPrototypeOf(parent)); // 输出false
// 所有对象的原型链最终都指向Object.prototype
console.log(Object.prototype.isPrototypeOf(child)); // 输出true
这种方式的优点是语义清晰,直接表达判断原型链祖先的意图,不需要额外的操作,兼容性也比较好,支持所有现代浏览器和Node.js环境。
使用instanceof运算符判断
instanceof是JavaScript的运算符,用于判断一个构造函数的prototype属性是否出现在某个实例对象的原型链上,它也可以间接用来判断原型链祖先关系,但使用场景有一定限制。
使用示例如下:
// 定义构造函数
function Parent() {}
function Child() {}
// 设置Child的原型为Parent的实例,形成继承关系
Child.prototype = new Parent();
// 创建Child的实例
const childInstance = new Child();
// 判断Parent.prototype是否在childInstance的原型链上
console.log(childInstance instanceof Parent); // 输出true,说明Parent的原型是childInstance的原型链祖先
console.log(childInstance instanceof Child); // 输出true
// 基础类型使用instanceof会返回false
const num = 1;
console.log(num instanceof Number); // 输出false,因为num是原始类型,不是Number的实例
const numObj = new Number(1);
console.log(numObj instanceof Number); // 输出true
需要注意的是,instanceof判断的是构造函数的prototype属性,而不是直接判断对象本身,如果要判断普通对象A是否是对象B的原型链祖先,不能直接用instanceof,需要先将A作为某个构造函数的prototype,再判断B的实例是否符合条件,使用场景比isPrototypeOf更局限。
手动遍历原型链判断
如果不想使用内置方法,也可以通过手动遍历原型链的方式判断,核心是通过Object.getPrototypeOf方法不断获取对象的原型,直到原型为null为止,检查目标对象是否出现在遍历路径中。
实现示例如下:
function isPrototypeAncestor(target, source) {
// 边界判断,target或source不是对象时直接返回false
if (target === null || typeof target !== 'object') return false;
if (source === null || typeof source !== 'object') return false;
let currentProto = Object.getPrototypeOf(source);
// 遍历原型链,直到currentProto为null
while (currentProto !== null) {
if (currentProto === target) {
return true;
}
currentProto = Object.getPrototypeOf(currentProto);
}
return false;
}
// 测试示例
const obj1 = { a: 1 };
const obj2 = Object.create(obj1);
const obj3 = Object.create(obj2);
console.log(isPrototypeAncestor(obj1, obj2)); // 输出true
console.log(isPrototypeAncestor(obj1, obj3)); // 输出true
console.log(isPrototypeAncestor(obj2, obj3)); // 输出true
console.log(isPrototypeAncestor(obj3, obj1)); // 输出false
这种方式的优点是可以完全自定义判断逻辑,比如增加额外的过滤条件,缺点是需要自己处理边界情况,代码量比使用内置方法更多。
不同方法的适用场景对比
我们可以通过表格对比三种判断方式的特点:
| 判断方式 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|
| isPrototypeOf | 直接判断任意对象是否是另一个对象的原型链祖先 | 语义清晰,使用简单,兼容性好 | 无明显的缺点,是最推荐的方式 |
| instanceof | 判断构造函数的原型是否在实例的原型链上 | 语法简洁,适合实例和构造函数的关系判断 | 只能判断构造函数prototype,不能直接判断普通对象 |
| 手动遍历 | 需要自定义原型链遍历逻辑的场景 | 灵活度高,可自定义逻辑 | 代码量多,需要处理边界情况 |
注意事项
在实际判断时需要注意几个问题:
- 原始类型(如数字、字符串、布尔值)没有原型链,判断时会返回false,比如
1的原型是Number.prototype,但直接使用Number.prototype.isPrototypeOf(1)会返回false,因为1是原始类型,不是对象。 - 如果修改了对象的原型,判断结果会随之变化,比如通过
Object.setPrototypeOf修改对象的原型后,之前的判断结果可能不再成立。 - 不要混淆
Object.getPrototypeOf和obj.__proto__,后者是非标准的属性,虽然大部分环境支持,但推荐优先使用标准的Object.getPrototypeOf。
总结来说,判断一个对象是否是另一个对象的原型链祖先,优先使用isPrototypeOf方法,它语义明确,使用简单,能够满足绝大多数场景的需求。如果是判断实例和构造函数的关系,可以使用instanceof。如果需要自定义遍历逻辑,再考虑手动遍历原型链的方式。
JavaScript原型链Object_getPrototypeOfisPrototypeOfinstanceof修改时间:2026-07-20 18:21:19