模块脚本本身不污染全局,但需开发者主动设计作用域、显式暴露接口并全程隔离;启用type="module"可触发严格模式与顶层作用域隔离,杜绝隐式挂载,而普通script、第三方SDK及SSR内联脚本仍是主要污染源。

模块脚本本身不污染全局,但“杜绝污染”不是靠模块自动生效,而是靠开发者守住几条关键边界。真正安全的模块作用域,需要主动设计、显式暴露、全程隔离。
用 type="module" 启动真正的隔离起点
浏览器对 <script type="module"> 默认启用严格模式 + 顶层作用域隔离:模块内用 let、const、function 声明的变量,不会挂到 window 上,也无法被其他脚本直接读取。
- 必须显式写
type="module",哪怕只是空标签:<script type="module"></script> - 模块脚本默认具有
defer行为,不阻塞 HTML 解析 - IE 不支持,但所有现代浏览器(Chrome 61+、Firefox 60+、Safari 10.1+)均可用
拒绝隐式挂载:警惕所有 window.xxx = ... 路径
ESM 不自动污染,但你可以手动污染。只要出现以下任一写法,就等于主动打开全局泄漏闸门:
-
window.api = fetchApi或globalThis.utils = {} -
window.addEventListener('load', init)中init是未声明函数(隐式全局) - 模块内用
eval('x = 1')且在非严格上下文(极少见,但存在风险) - 第三方 SDK、统计脚本、广告代码——它们大多仍以普通
<script>方式加载,是当前最常见污染源
混合加载时,污染往往来自“非模块那一半”
一个页面常同时存在 <script> 和 <script type="module">。此时:
- 普通
<script>中的var a = 1仍等价于window.a = 1,模块脚本完全感知不到这个a - 旧库(如 jQuery 插件)若内部执行
this.xxx = y且this === window,就会悄悄写入全局 - 服务端渲染(SSR)内联的
<script>片段、document.write()注入的脚本,也绕过模块隔离
验证与排查:三行控制台命令快速定位异常
打开 DevTools 控制台,运行以下语句即可发现可疑绑定:
-
Object.keys(window).filter(k => k.startsWith('_') || k.length < 4)—— 找短名或下划线前缀变量 -
console.log(window.myTool, window.config, window.utils)—— 检查常用命名空间是否被意外覆盖 -
Object.getOwnPropertyDescriptor(window, 'xxx')—— 查看属性是否configurable: false或enumerable: false(正常模块不会设这些)

















