
本文详解解决 document.write 在 iframe 中重复执行导致 JavaScript 变量重声明错误(如 “Identifier 'x' has already been declared”)的根本方案,推荐使用 Blob URL 方式替代 document.write,兼顾兼容性、安全性与可维护性。
本文详解解决 `document.write` 在 iframe 中重复执行导致 javascript 变量重声明错误(如 “identifier 'x' has already been declared”)的根本方案,推荐使用 blob url 方式替代 `document.write`,兼顾兼容性、安全性与可维护性。
在构建 HTML/CSS/JS 实时编辑器时,开发者常通过 iframe.contentDocument.write() 将用户输入的代码写入 iframe 进行预览。但该方式存在严重缺陷:每次调用 write() 会完全销毁并重建 iframe 的文档上下文,导致其中已执行的 <script>(尤其是 const/let 声明)在下次重写时被重复解析,触发语法错误 —— 这正是 Identifier 'p' has already been declared 的根源。</script>
直接使用 try...catch 捕获此类语法错误是无效的:它无法阻止解析阶段的失败,也无法恢复执行环境;而简单清空 iframe 后重写,仍无法规避变量重声明问题。真正可靠的解法是避免复用同一文档上下文,转而为每次更新创建全新的、隔离的文档实例。
✅ 推荐方案:Blob URL(安全、兼容、语义清晰)
Blob URL 利用 URL.createObjectURL(new Blob([html], {type: 'text/html'})) 生成一个指向动态 HTML 内容的唯一地址,并赋值给 iframe 的 src 属性。其核心优势在于:
- 无上下文残留:每次更新都加载全新文档,彻底规避变量重声明;
- 同源隔离:Blob URL 具有独立 origin(blob: 协议),脚本无法访问父页面 DOM 或变量,天然防 XSS;
- 广泛兼容:支持所有现代浏览器及 IE10+,无需 polyfill;
- 自动资源管理:配合 iframe.onload 调用 URL.revokeObjectURL() 可及时释放内存。
以下是生产就绪的实现代码(含防抖优化):
<textarea id="editor" spellcheck="false"></textarea><iframe id="preview" src="about:blank"></iframe>
<style>
#editor, #preview {
width: 400px;
height: 300px;
border: 1px solid #ccc;
}
</style><script>
const textarea = document.getElementById('editor');
const iframe = document.getElementById('preview');
// 防抖函数:避免高频输入导致 iframe 频繁重载
function debounce(func, delay) {
let timer;
return function (...args) {
clearTimeout(timer);
timer = setTimeout(() => func.apply(this, args), delay);
};
}
function preview() {
const html = textarea.value.trim() || '<!DOCTYPE html><html><body><p>No content</script>
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











