本质是跨Realm导致类型判断失准:iframe跨域后形成独立执行环境,内置构造函数不共享,Array.isArray()等检测失效;应改用Object.prototype.toString.call()或结构化判断。

这个问题本质不是“拷贝失效”,而是跨 Realm(执行环境)导致的类型判断失准。iframe 一旦跨域,就形成独立的 JavaScript 执行上下文(即独立 Realm),每个 Realm 都有自己的一套内置构造函数(如 Array、Date、Promise 等)。即使你把一个数组从父页面传进 iframe(比如通过 postMessage 序列化再反序列化,或用 window.name 等方式“带过去”),它在 iframe 里也不再是 iframe 自身 Realm 中的 Array——它的原型链指向的是父页面的 Array.prototype,而 iframe.Array !== parent.Array。
怎么识别这种类型判定失效?
典型表现是:你在 iframe 里对收到的对象调用 Array.isArray()、instanceof Array、obj.constructor === Array 全部返回 false,哪怕它看起来就是个标准数组;同理,Object.prototype.toString.call(obj) 可能返回 "[object Object]" 而非预期的 "[object Array]"。
哪些操作会触发这个现象?
- 使用
postMessage传递对象:自动序列化/反序列化后,所有引用类型都变成“普通对象”,原始构造器信息丢失 - 通过
window.name或location.hash传 JSON 字符串,再JSON.parse():结果必为 plain object,无构造器痕迹 - 跨域 iframe 中直接访问父页面变量(被浏览器阻止,但若误以为可行而写代码,逻辑就会崩在类型判断上)
- 用
structuredClone()(现代 API):虽保留部分类型,但跨 Realm 时仍无法还原为当前 Realm 的原生构造实例
真正可靠的类型检测方法
放弃依赖构造器和 instanceof,改用行为或结构判断:
-
数组:用
Array.isArray(obj)是最安全的(它不依赖obj.constructor,而是检查内部 [[Class]] 标签) -
日期:用
obj instanceof Date不可靠 → 改用Object.prototype.toString.call(obj) === '[object Date]'或typeof obj === 'object' && !isNaN(Date.parse(obj)) -
正则:同理,
Object.prototype.toString.call(obj) === '[object RegExp]' -
普通对象/类数组:优先用
obj != null && typeof obj === 'object' && obj.constructor === Object(注意:仅当确认同 Realm 时才安全);更通用做法是Object.prototype.toString.call(obj)+ 白名单比对
避免踩坑的实践建议
- 跨域 iframe 通信中,约定数据结构为纯 JSON 兼容格式(字符串、数字、布尔、null、普通对象、数组),不传函数、Date、RegExp、Blob 等非可序列化类型
- 如必须传递特殊类型,由双方约定统一的序列化协议(例如:
{ $type: 'date', value: '2026-05-01T16:26:00Z' }),接收方按规则重建 - 不要在 iframe 里对跨域传入的对象做
obj instanceof SomeClass判断——它几乎总为false - 调试时可用
console.dir(obj)查看其__proto__链,确认是否指向当前 iframe 的Array.prototype还是别的 Realm 的










