最新下载
热门教程
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
如何利用 structuredClone 拷贝具备 Blob 或 File 原始属性的复杂表单对象
时间:2026-06-13 09:50:04 编辑:袖梨 来源:一聚教程网
structuredClone()可安全深拷贝含Blob/File/FormData等对象的表单数据,但需确保浏览器支持(Chrome 98+/Firefox 97+/Safari 15.4+/Node.js 17.0+),对不支持环境需降级处理;克隆要求Blob/File为原生实例,元数据应独立存储;克隆后Blob引用有效,但object URL需重新生成;FormData需先转为键值对再克隆。
structuredClone() 可以安全深拷贝包含 Blob、File、FormData、Map、Set 等可转移对象的表单数据,但需注意浏览器兼容性与特殊限制。
确认环境支持并处理不支持场景
structuredClone() 在现代浏览器(Chrome 98+、Firefox 97+、Safari 15.4+)中可用,Node.js 17.0+ 也支持。若需兼容旧环境,应降级使用 Blob.slice() 手动重建 Blob,或借助 FileReader + ArrayBuffer 序列化再反序列化。
- 检查支持:if (typeof structuredClone === 'function') { ... }
- 不支持时,对含 Blob/File 的对象,避免直接 JSON.stringify(会丢失二进制内容)
- 可封装 fallback 函数:对 Blob 创建新实例(new Blob([blob], {type: blob.type})),对 File 需额外传入 name 和 lastModified(File 构造函数支持)
正确构造含 Blob/File 的表单对象
structuredClone 要求原始对象中的 Blob/File 必须是“可结构化克隆”的值——即原生实例,而非被 Proxy 包裹、或经自定义属性扩展的对象。例如,直接从 input[type="file"].files[0] 获取的 File 实例可被克隆;但若手动添加了 .customId 等属性,克隆后该属性会丢失(structuredClone 不保留非自有可枚举属性)。
- 确保 Blob/File 是原生实例,未被 Object.assign 或解构修改原型
- 如需携带元数据(如上传 ID、标签),建议用独立字段保存,而非挂载在 Blob/File 实例上
- 示例安全结构:
{ file: input.files[0], metadata: { id: 'xxx', tag: 'avatar' } }
克隆后保持文件引用有效性
structuredClone 会创建新的 Blob/File 实例,其内容与原实例共享底层字节(通过内部引用计数),因此克隆后的 Blob 仍可正常读取、上传或转为 URL(URL.createObjectURL())。但注意:克隆不会复制已生成的 object URL,需对新 Blob 单独调用 URL.createObjectURL()。
- 克隆前后 Blob.size、.type、.name(File)均保持一致
- 克隆后的 File 实例仍是 instanceof File,可直接用于 FormData.append()
- 若原 Blob 来自 fetch 响应,克隆后仍可流式读取(.stream() 有效)
与 FormData 配合使用的注意事项
structuredClone 本身不支持直接克隆 FormData(它不是可结构化类型),但可先将其转换为普通对象或数组,再克隆。推荐方式是遍历 FormData.entries(),提取键值对,对 Blob/File 值直接保留,其他值按需处理:
- const formObj = Array.from(formData.entries()).reduce((acc, [k, v]) => ({ ...acc, [k]: v }), {})
- 再用 structuredClone(formObj) 得到深拷贝对象
- 如需还原为 FormData,遍历克隆后的对象,对每个值调用 new FormData().append(k, v)
- 注意:FormData 中同名多值(如多个 checkbox)会被 entries() 按顺序展开,还原时需确保 append 顺序一致