instanceof(原型链判断)

8 小时前
/ ,
1

instanceof(原型链判断)

instanceof 用来判断:某个对象的原型链上,是否能找到某个构造函数的 prototype

obj instanceof Ctor

结论先说

  • instanceof 判断的是 原型链关系,不是“类型”本身。
  • 左侧必须是对象(或函数),原始类型(1 / 'a' / true / null / undefined)一般都是 false
  • 右侧必须是“可作为构造器/有 prototype 的对象”(通常是函数),否则会抛 TypeError

运行机制(核心原理)

在不考虑 Symbol.hasInstance 的情况下,x instanceof F 大致等价于:

1) 取到 F.prototype 2) 从 x 开始沿着 [[Prototype]](也就是 Object.getPrototypeOf(x))一直向上找 3) 如果某一层原型 === F.prototype,返回 true 4) 找到 null 还没找到,则返回 false

手写实现(推荐:循环版,避免递归栈)

/**
 * 模拟默认语义:判断 ctor.prototype 是否在 obj 的原型链上
 * 不包含 Symbol.hasInstance 的自定义逻辑
 */
export function myInstanceof(obj: unknown, ctor: any): boolean {
    // 1) 原始值一定不是实例
    if (obj === null || obj === undefined) return false;
    const t = typeof obj;
    if (t !== 'object' && t !== 'function') return false;

    // 2) 右侧必须是对象/函数,并且要有可用的 prototype
    // 原生 instanceof 在不合法时会抛 TypeError
    if (ctor === null || (typeof ctor !== 'function' && typeof ctor !== 'object')) {
        throw new TypeError('Right-hand side of instanceof is not an object');
    }
    const proto = (ctor as any).prototype;
    if (proto === null || (typeof proto !== 'object' && typeof proto !== 'function')) {
        throw new TypeError('Function has non-object prototype in instanceof check');
    }

    // 3) 沿原型链向上查找
    let cur = Object.getPrototypeOf(obj as object);
    while (cur !== null) {
        if (cur === proto) return true;
        cur = Object.getPrototypeOf(cur);
    }
    return false;
}

示例

function Person() {}
const p = new (Person as any)();

myInstanceof(p, Person); // true
myInstanceof(p, Object); // true
myInstanceof({}, Person); // false
myInstanceof(1 as any, Number); // false(原始值)

常见坑点

1) 跨 iframe / 跨 realm

不同 realm(例如 iframe)里有不同的全局构造函数:

  • 另一个 iframe 创建的数组,arr instanceof Array(当前窗口的 Array)可能是 false

这种场景更推荐用:

  • Array.isArray(x)
  • Object.prototype.toString.call(x)

2) prototype 可被篡改

Ctor.prototype 或对象的原型链都能被改,instanceof 结果也会变。

3) Object.create(null) 没有原型

const x = Object.create(null);
x instanceof Object; // false

与 typeof / toString 的对比

  • typeof:适合区分原始类型与函数(例如 typeof fn === 'function'),但对对象细分能力弱(数组/日期/正则都返回 'object'
  • instanceof:适合判断“是否由某构造函数的原型链派生”,但跨 realm 容易踩坑
  • Object.prototype.toString.call(x):更稳定地识别内置类型([object Array] / [object Date] 等)

使用社交账号登录

  • Loading...
  • Loading...
  • Loading...
  • Loading...
  • Loading...