模块化从根源上切断代码自动挂入全局作用域的路径,使每个文件拥有独立作用域边界,顶层声明的变量函数仅在本模块有效,不会污染window或global,未显式export即私有。

模块化从根源上切断了代码自动挂入全局作用域的路径,让每个文件拥有独立的作用域边界,不再默认向 window 或 global 泄漏变量。
模块系统天然隔离作用域
ES6 模块(import/export)和 CommonJS(require/module.exports)都规定:模块顶层声明的 const、let、function 等,只在当前模块内有效。它们不会像普通脚本那样自动成为全局属性。
- 即使你写
const api = 'https://example.com';,它也不会出现在window.api中 - 只有显式
export的内容才能被其他模块访问,未导出即私有 - 打包工具(如 Vite、Webpack)会把每个模块包裹进独立函数作用域,进一步加固隔离
避免 script 标签直连老库
很多全局污染来自直接用 <script src="xxx.js"></script> 引入第三方库——这类脚本执行时直接运行在全局上下文,极易挂载 $、Chart、moment 等到 window 上。
- 改用
import方式引入,例如import $ from 'jquery',让打包器接管加载逻辑 - 优先选用提供 ESM 版本的库(查看其
package.json中的"type": "module"或"exports"字段) - 对仍输出全局变量的老库,可在打包配置中设为
externals,或手动删掉window.$
无法模块化的代码要主动封装
有些遗留脚本不支持 import,又必须运行,这时不能放任它自由污染。
- 用 IIFE 包裹:在执行前加上
(function () { "use strict"; /* 原始代码 */ })(); - 启用严格模式可防止意外创建全局变量(比如忘了写
var/let就赋值) - 若库必须暴露接口,显式挂到唯一命名空间下,如
MyApp.ThirdParty = window.Chart;,随后delete window.Chart
CSS 和类型定义也要同步隔离
全局污染不限于 JS 变量,样式和类型同样需要作用域意识。
- CSS:用 CSS Modules 或
:global(.btn) {...}显式控制第三方类名生效范围,避免.button覆盖全站 - TypeScript:通过
declare module 'xxx'精确导入类型,不用泛滥的declare global - 构建时开启
noImplicitAny和isolatedModules,提前拦截潜在泄漏点











