闭包实现脚本沙盒容器的核心是函数作用域天然隔离与显式暴露接口,通过iife创建私有空间、按需注入受控上下文、封装执行逻辑拦截副作用,并支持单例缓存与内部事件通信。

用闭包实现脚本沙盒容器,核心是靠函数作用域天然隔离 + 显式控制暴露接口,不依赖 iframe 或 Proxy 就能达成轻量、可控的执行环境隔离。
构造封闭作用域作为基础沙箱
闭包最直接的价值是创建一个外部不可见的私有空间。把所有内部变量、辅助函数都定义在自执行函数(IIFE)或工厂函数内,它们就自动与全局隔开:
- 用 (function() { /* 私有逻辑 */ })(); 包裹整段沙箱代码,避免污染全局
- 若需对外提供能力,只通过返回对象暴露有限方法,如 return { run: function() {}, getLog: function() {} }
- 内部变量(如 let cache = new Map())完全不可从外部读写,连 typeof 都无法探测
按需注入受控上下文对象
沙箱不是完全空白环境,而是要有选择地提供安全 API。把允许访问的对象(如 DOM 查询结果、配置项、工具函数)作为参数传入闭包,而非直接引用 window 或 document:
- 写成 createSandbox({ el: document.getElementById('app'), utils: safeUtils })
- 闭包内部只操作这个传入对象的属性,不触碰任何隐式外部引用
- 这样既满足功能需要,又防止脚本偷偷调用 fetch、localStorage 等高危 API
封装执行逻辑并拦截副作用
真正执行用户脚本时,不能直接 eval 或 new Function——那会逃出闭包约束。正确做法是把脚本逻辑转为预定义行为:
- 例如支持“点击按钮后修改文本”,就只暴露 onButtonClick(cb) 方法,cb 内部只能调用沙箱提供的 setText(id, content)
- 所有 DOM 操作由沙箱统一代理,可加日志、限频、白名单校验
- 异步操作(如模拟请求)用 Promise 封装,resolve 前检查响应结构是否合规
配合单例与缓存提升实用性
实际插件或编辑器中,沙箱常需复用。闭包可自然支撑这些模式:
- 用闭包保存唯一实例:const instance = (function() { let core; return () => core || (core = init()); })();
- 缓存频繁查询的节点:const $btn = cachedQuery('#submit');,该函数在闭包内维护 Map
- 模块间通信走沙箱内部事件总线,不依赖 CustomEvent 或 dispatchEvent,彻底切断与页面事件流的耦合











