先记住这个答案
在普通构造器语义下,instanceof 检查右侧构造器的 prototype 是否出现在左侧对象的原型链中,TypeScript 可以据此在分支内收窄到对应实例类型。来自另一个 iframe 或 realm 的实例可能使用另一份构造器和原型,即使看起来同类,对当前 realm 构造器的检查也可能失败。它适合受控来源的类实例,不适合验证普通 JSON 是否符合接口。跨来源数组通常用 Array.isArray,业务数据则需要字段解析;自定义 Symbol.hasInstance 还可能改变默认判断行为。
- 普通 instanceof 依赖具体构造器与原型链
- 跨 realm 或多份类定义可能拥有不同身份
- 接口与普通 JSON 没有自动对应的实例关系
同名字段为什么不等于类实例
结构类型检查可能允许某个普通对象满足公共接口,但 instanceof 在运行时关心另一种关系。一个字面量即使提供相同字段,也通常没有该类的原型。类实例适配与普通数据验证应分开设计,避免把两套规则混为一谈。
示例接收自定义错误或字符串,实例分支能够访问错误专有的状态码,文本分支则使用字符串方法。这里构造器来源完全受控,因此实例判断有明确意义。若消息已经经过 JSON 序列化,就不能期待反序列化对象自动恢复这个原型。
class ApiFailure extends Error {
constructor(public status: number, message: string) {
super(message);
}
}
function explain(value: ApiFailure | string): string {
if (value instanceof ApiFailure) return value.status + ': ' + value.message;
return value.trim();
}
const instance = new ApiFailure(503, 'busy');
const text = explain(instance);
const ordinary = { status: 503, message: 'busy' };真实 ApiFailure 实例进入状态码分支,普通对象 ordinary 即使拥有相似字段也不自动成为该类实例。示例依赖现代 JavaScript 类运行语义,不把序列化数据当成已经恢复原型的实例。
iframe 与重复打包为何造成身份差异
不同 realm 可以拥有各自的 Array、Error 等内建构造器和原型对象。一个 iframe 创建的数组拿到父页面后,检查父页面的 Array 可能为假,但它仍然是数组。类似问题也可能来自同一库的两份安装或重复打包生成的独立类定义。
跨边界契约应优先使用稳定的数据协议,或者确保构造器实例确实共享。识别数组时,Array.isArray 面向数组自身的内部识别,适合处理这类跨 realm 情况。自定义业务对象则通常要检查字段与版本,不能照搬数组专用方法解决全部身份问题。
特殊行为与异常值还需要处理
构造器可以通过 Symbol.hasInstance 自定义判断逻辑,所以原型链解释应明确默认前提。类型系统信任这种守卫提供的关系,不会自动证明自定义实现与类契约完全一致。框架或库若重写这一行为,调用方需要阅读其公开约定。
捕获异常时,抛出的值也可能是字符串或其他对象。instanceof Error 失败不代表没有错误信息,更不代表该值安全;可以使用明确的后备格式化方式处理未知异常。避免为了统一展示而断言所有异常都有 message,这会把新的读取错误叠加到原错误之上。
容易答错的地方
- 对象字段与类相同就一定 instanceof 为真
- 默认判断依赖原型链与具体构造器身份,结构相似不足以建立这种关系;从 JSON 得到的普通对象尤其不能直接当类实例。
- 跨 iframe 判断失败说明不是数组
- 另一个 realm 的数组可能不继承当前 Array.prototype,仍然具有数组身份;识别数组应使用适合跨 realm 的 Array.isArray。
面试官还会怎么问?
可以把 interface 放在 instanceof 右边吗?
不可以,普通接口只存在于类型层,运行时没有相应构造器值;需要使用真实类、明确标签或检查字段的解析函数。
同一个类名的两份库会被当作相同类吗?
运行时名称相同并不等于构造器引用相同,两份独立定义通常拥有不同原型;需要统一依赖来源或改用跨边界的数据协议。
恢复 JSON 数据时设置原型就等于完成校验吗?
不等于,修改原型不会检查字段是否合法或补齐构造器不变量;应先解析数据,再通过受控构造入口创建满足契约的实例。
参考资料
示例用于理解所注明的运行环境与边界;延伸学习可结合原文中的更多案例。