自定义instanceof运算符行为API: Symbol.hasInstance

今天翻zod的源码,发现有个之前没见过的,应该也没听说的API:Symbol.hasInstance

ts 复制代码
export /*@__NO_SIDE_EFFECTS__*/ function $constructor<T extends ZodTrait, D = T["_zod"]["def"]>(
  name: string,
  initializer: (inst: T, def: D) => void,
  params?: { Parent?: typeof Class }
): $constructor<T, D> {
  // ...
  // 
  Object.defineProperty(_, Symbol.hasInstance, {
    value: (inst: any) => {
      if (params?.Parent && inst instanceof params.Parent) return true;
      return inst?._zod?.traits?.has(name);
    },
  });
}

发现有个写了几年代码都没发现的API,就拿去问ai了。


Symbol.hasInstance是 JavaScript 的一个内置 Symbol,用于自定义 instanceof运算符的行为

基本用法

默认情况下,instanceof检查对象的原型链:

js 复制代码
class Animal {}
class Dog extends Animal {}

const dog = new Dog();
console.log(dog instanceof Dog);     // true
console.log(dog instanceof Animal);   // true
console.log(dog instanceof Object);   // true

使用 Symbol.hasInstance 自定义行为

你可以通过定义静态的 Symbol.hasInstance方法来改变 instanceof的行为:

js 复制代码
class MyClass {
    static [Symbol.hasInstance](instance) {
        // 自定义判断逻辑
        return typeof instance === 'object' && 
               instance !== null && 
               instance.value === 42;
    }
}

const obj1 = { value: 42 };
const obj2 = { value: 100 };
const obj3 = null;

console.log(obj1 instanceof MyClass); // true
console.log(obj2 instanceof MyClass); // false
console.log(obj3 instanceof MyClass); // false

实际应用场景

1. 基于属性的实例检查

js 复制代码
class Validator {
    static [Symbol.hasInstance](obj) {
        return typeof obj === 'object' && 
               obj !== null && 
               typeof obj.validate === 'function';
    }
}

const validObj = {
    validate() { return true; }
};

const invalidObj = { name: "test" };

console.log(validObj instanceof Validator);   // true
console.log(invalidObj instanceof Validator);  // false

2. 数字范围检查

js 复制代码
class PrimeNumber {
    static isPrime(num) {
        if (num <= 1) return false;
        for (let i = 2; i <= Math.sqrt(num); i++) {
            if (num % i === 0) return false;
        }
        return true;
    }
    
    static [Symbol.hasInstance](num) {
        return Number.isInteger(num) && this.isPrime(num);
    }
}

console.log(2 instanceof PrimeNumber);    // true
console.log(7 instanceof PrimeNumber);    // true
console.log(4 instanceof PrimeNumber);    // false
console.log(9 instanceof PrimeNumber);    // false

3. 数组内容检查

js 复制代码
class NumericArray {
    static [Symbol.hasInstance](arr) {
        return Array.isArray(arr) && 
               arr.every(item => typeof item === 'number');
    }
}

console.log([1, 2, 3] instanceof NumericArray);     // true
console.log([1, '2', 3] instanceof NumericArray);   // false

注意事项

  1. 1.必须是静态方法Symbol.hasInstance必须定义为类的静态方法
  2. 2.影响所有 instanceof 检查:会改变该类的所有实例检查行为
  3. 3.谨慎使用:过度使用可能使代码难以理解
js 复制代码
class CustomClass {
    // 正确:静态方法
    static [Symbol.hasInstance](instance) {
        return true; // 所有对象都是实例
    }
    
    // 错误:实例方法(不会生效)
    [Symbol.hasInstance](instance) {
        return false;
    }
}

console.log({} instanceof CustomClass); // true(总是返回 true)

总结

Symbol.hasInstance的主要用途是让开发者能够自定义 instanceof运算符的逻辑,实现更灵活的类型检查机制。这在创建验证器、特殊数据类型的类或者需要复杂实例检查的场景中非常有用。

为什么这样设计

  • 灵活性:允许对象通过特征标记而非严格的类继承来表示类型
  • 组合优于继承:支持特征组合,一个对象可以有多个特征
  • 运行时类型检查:可以在运行时动态添加/移除类型特征

这种模式在需要灵活类型系统的库中很常见,特别是那些需要支持动态类型或混合类型的场景。

相关推荐
J***Q2923 小时前
Vue数据可视化
前端·vue.js·信息可视化
ttod_qzstudio5 小时前
深入理解 Vue 3 的 h 函数:构建动态 UI 的利器
前端·vue.js
_大龄5 小时前
前端解析excel
前端·excel
一叶茶5 小时前
移动端平板打开的三种模式。
前端·javascript
前端大卫5 小时前
一文搞懂 Webpack 分包:async、initial 与 all 的区别【附源码】
前端
Want5956 小时前
HTML音乐圣诞树
前端·html
老前端的功夫6 小时前
前端浏览器缓存深度解析:从网络请求到极致性能优化
前端·javascript·网络·缓存·性能优化
Running_slave7 小时前
你应该了解的TCP滑窗
前端·网络协议·tcp/ip
程序员小寒7 小时前
前端高频面试题之CSS篇(一)
前端·css·面试·css3
颜酱7 小时前
Monorepo 架构以及工具选型、搭建
前端·javascript·node.js