应检查window上是否存在异常新增或卸载后残留的业务相关属性,如__myApp_init等,重点排查显式/隐式挂载、this绑定错误、沙箱绕过及高频危险写法。

直接看 window 上有没有不该存在的函数或对象,尤其是那些名字带业务特征、模块名或组件名的属性。
检查 window 属性是否异常新增或持久化
子应用卸载后,执行 console.log(Object.keys(window)),对比激活前后的键列表。若发现如 __myApp_init、handleClickFromLogin、fetchInterceptor 这类明显来自子应用的属性仍存在,大概率是闭包被意外挂到全局。
- 重点排查:子应用代码中是否用了
window.xxx = function() {...}或window[customKey] = closure - 注意隐式挂载:非严格模式下漏写
var/let/const,比如render = () => {...}会自动变成window.render - 检查
this绑定错误:如function init() { this.loader = () => {...} }在非严格模式下调用,this指向window,loader 就成了全局闭包
用 DevTools 快照定位闭包持有者
在子应用加载并卸载后,打开 Chrome DevTools → Memory → Take Heap Snapshot,筛选类型为 Closure,再按关键词(如组件名、API 名)搜索。
- 点开可疑闭包,在右侧 Retainers 栏查看引用链:如果路径里出现
window→xxx→Closure,说明该闭包正被 window 直接持有 - 特别关注
Retained Size偏大的 Closure,它往往捕获了 DOM 节点、大数组或整个状态对象 - 配合 Comparison 视图:多次操作后对比快照,若某 Closure 实例数持续增长,且都挂在 window 下,基本可确认泄漏源头
验证沙箱是否被绕过导致劫持失效
微前端场景下,闭包挂 window 往往伴随沙箱失效——比如子应用用了 eval、new Function 或 with,绕过了 qiankun 的属性代理逻辑,让原本该被隔离的赋值直接落到真实 window 上。
- 在子应用入口加断点,检查
window.__POWERED_BY_QIANKUN__是否存在,以及window.fetch等 API 是否仍为原始函数(而非沙箱重写的版本) - 搜索代码中是否存在
eval(、new Function(、with (等高风险语法 - 运行时打印
Object.getOwnPropertyNames(window).filter(k => k.includes('my')),看是否有预期外的 key 出现在真实 window 而非沙箱 proxy 中
快速自查高频危险写法
以下写法极易导致闭包意外挂 window,建议逐行扫描子应用初始化逻辑:
-
function setup() { handler = () => console.log(data) }—— 缺声明,handler成全局 -
class Plugin { init() { window.pluginCallback = this.onEvent.bind(this) } }—— 显式挂载未清理 -
const mod = require('./utils'); window.utils = mod;—— 模块导出对象含闭包方法,又挂到 window -
document.addEventListener('click', e => { /* 闭包内调用 window.api */ })—— 若事件监听器未解绑,闭包长期存活并维持对 window 的引用

















