小程序和快应用禁用全局变量是出于安全设计,闭包通过作用域延续实现可控共享:文件被包裹为立即执行函数形成天然闭包,封装私有状态并导出受控api,既防污染又支持轻量单例与异步上下文固化。

小程序和快应用都默认禁用全局变量,比如不能直接挂载 window 或 globalThis,也不允许模块间自由共享顶层变量。这种限制不是缺陷,而是安全设计——防止脚本污染、避免跨页面状态冲突。闭包正是绕过该限制、实现“可控共享”的自然解法。
闭包本质是作用域的延续
每个小程序 JS 文件在构建时都会被包裹成一个立即执行函数:
(function(exports, require, module, __filename, __dirname) { /* 你的代码 */ })
这个包装本身就是一个闭包环境。所有在文件顶层声明的变量(非 var 声明在全局)天然被封在该函数作用域内,既不暴露给其他页面,也不会被外部篡改。
用闭包封装可复用的状态与工具
把需要跨函数/跨请求保持的数据或逻辑,封装进一个返回对象的闭包函数里:
- 定义一个初始化函数,内部维护私有变量(如 token、缓存 map、计数器)
- 返回一组受控方法(get/set/refresh),只暴露必要接口
- 在 app.js 或 utils 目录中调用一次,导出实例,各页面 import 即可共用同一份隔离状态
这样既规避了全局污染,又实现了轻量级单例通信。
解决异步中变量丢失的经典问题
比如 wx.request 或快应用 fetch 在循环中发起请求时,var i 会因作用域提升导致全部取到终值。闭包可固化每次迭代的上下文:
- 用 (function(i) { ... })(i) 匿名自调用,把当前 i 封进参数作用域
- 或直接用 let i —— ES6 块级作用域天然形成闭包效果,更简洁可靠
- 对对象类数据,可传入引用并用闭包方法做深拷贝或标记,避免多个请求覆盖同一内存地址
配合模块系统做分层隔离
闭包不是万能胶,需和模块机制协同:
- 每个 .js 文件是一个独立模块,天然拥有自己的闭包顶层
- 通过 export 暴露闭包返回的 API,而非原始变量
- 避免在页面 onLoad 中反复 new 实例,统一由 store 或 manager 模块管理生命周期
- 快应用中还可结合 @hap/bridge 的 context 隔离能力,让闭包状态绑定到特定运行上下文











