应使用 object.getprototypeof(obj) === constructor.prototype 判定直接派生关系,因 instanceof 和 isprototypeof 会跨原型链匹配,无法区分直接与间接继承;需确保 constructor.prototype 未被篡改且非箭头函数。

要精准判定一个实例是否直接派生自某个构造函数的原型(即该实例的 [[Prototype]] 是否**严格等于**该构造函数的 prototype),应使用 Object.getPrototypeOf(obj) === Constructor.prototype,而非 instanceof 或 isPrototypeOf —— 因为后者会跨多层原型链匹配,无法区分“直接继承”与“间接继承”。
为什么不能用 instanceof
instanceof 检查的是整个原型链中是否存在指定构造函数的 prototype,只要在链上任意位置匹配就返回 true,无法体现“直接”关系。
function A() {}
function B() {}
B.prototype = Object.create(A.prototype);
const b = new B();
b instanceof B; // true(直接)
b instanceof A; // true(但只是间接:B → A)
Object.getPrototypeOf(b) === B.prototype; // true ✅
Object.getPrototypeOf(b) === A.prototype; // false ❌
正确写法:用 Object.getPrototypeOf 严格比对
这是唯一能准确捕捉“直接原型归属”的方式。关键点是:必须用全等运算符 ===,且确保右侧是目标构造函数的原始 prototype 对象(未被覆盖或重赋值)。
- 获取实例的内部原型:
Object.getPrototypeOf(obj) - 获取目标构造函数的原型对象:
Constructor.prototype - 用
===判断二者是否为同一对象(引用相等) - 注意:若构造函数的
prototype曾被整体替换(如C.prototype = {...}),需确保比对的是替换后的那个对象
常见陷阱与规避建议
实际使用中容易忽略几个细节,导致误判:
-
箭头函数没有
prototype:不能作为判定目标,否则ArrowFunc.prototype是undefined,比对必为false -
类的子类实例不满足父类的“直接”判定:即使
class C extends B,new C()的直接原型是C.prototype,不是B.prototype -
手动修改
__proto__会影响结果:如果运行时改过实例的__proto__,Object.getPrototypeOf返回的就是新值,此时判定反映的是当前状态,而非构造时关系 -
避免用字符串名动态查构造函数:比如
obj.constructor.name === 'Foo'不可靠——constructor可被篡改,且匿名类/函数无稳定名称
封装一个安全判定函数
可封装为可复用的工具函数,增强健壮性:
function isDirectInstance(obj, Constructor) {
if (obj == null || typeof Constructor !== 'function') return false;
if (Constructor.prototype == null) return false; // 如箭头函数
return Object.getPrototypeOf(obj) === Constructor.prototype;
}
// 使用示例
function Animal() {}
function Dog() {}
Dog.prototype = Object.create(Animal.prototype);
const dog = new Dog();
isDirectInstance(dog, Dog); // true
isDirectInstance(dog, Animal); // false
isDirectInstance(dog, Object); // false(dog.__proto__ 不是 Object.prototype)











