今天翻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.必须是静态方法 :
Symbol.hasInstance必须定义为类的静态方法 - 2.影响所有 instanceof 检查:会改变该类的所有实例检查行为
- 3.谨慎使用:过度使用可能使代码难以理解
js
class CustomClass {
// 正确:静态方法
static [Symbol.hasInstance](instance) {
return true; // 所有对象都是实例
}
// 错误:实例方法(不会生效)
[Symbol.hasInstance](instance) {
return false;
}
}
console.log({} instanceof CustomClass); // true(总是返回 true)
总结
Symbol.hasInstance的主要用途是让开发者能够自定义 instanceof运算符的逻辑,实现更灵活的类型检查机制。这在创建验证器、特殊数据类型的类或者需要复杂实例检查的场景中非常有用。
为什么这样设计
- 灵活性:允许对象通过特征标记而非严格的类继承来表示类型
- 组合优于继承:支持特征组合,一个对象可以有多个特征
- 运行时类型检查:可以在运行时动态添加/移除类型特征
这种模式在需要灵活类型系统的库中很常见,特别是那些需要支持动态类型或混合类型的场景。