尧图精选

ESLint no-native-reassign 规则深度解析:禁止覆盖只读全局变量及弃用迁移指南

🕒 发布时间:2026/9/12 13:58:42 📁 来源:尧图网络
ESLint no-native-reassign 规则深度解析禁止覆盖只读全局变量及弃用迁移指南【免费下载链接】eslintFind and fix problems in your JavaScript code.项目地址: https://gitcode.com/GitHub_Trending/es/eslint本文围绕 ESLint 核心规则no-native-reassign展开讲解它如何防止开发者误覆写window、Object、undefined等内置全局变量并通过源码级分析揭示其基于只读全局变量与写引用的检测原理。读完本文你将掌握该规则的完整配置方法含exceptions选项、它与no-undef、no-global-assign的关联脉络以及从no-native-reassign平滑迁移到no-global-assign的实操方案。为什么不能给内置全局变量赋值JavaScript 运行环境内置了大量全局变量例如浏览器中的window、Node.js 中的process。绝大多数情况下你不应该给这些全局变量重新赋值——一旦覆盖就可能永久丢失对关键功能的访问。例如在浏览器代码中下面的写法几乎总是错误window {};window这种例子比较显而易见但实际环境中内置全局对象往往数以百计开发者很难逐一判断我此刻赋值的名字是不是某个内置全局变量。no-native-reassign规则正是为这个问题而生它利用 ESLint 对全局变量可写/只读状态的跟踪能力自动拦截对只读全局变量的修改。从版本演化看本规则从 v0.0.9 起随 ESLint 存在见 docs/src/_data/rule_versions.json其历史可以追溯到它原先作为no-undef规则的一部分见 docs/src/use/migrating-to-3.0.0.md。规则详情它到底检测什么规则的核心声明是禁止修改只读read-only的全局变量原文见 docs/src/rules/no-native-reassign.md。这里的关键在于只读二字——ESLint 本身具备把全局变量配置为只读的能力规则针对的不仅是原生内置对象也包括任何被显式声明为只读的全局变量。源码级原理从Program节点到Reference打开规则实现 lib/rules/no-native-reassign.js可以看到检测逻辑非常精巧总共只有三个关键函数create(context)入口。先读取配置context.options[0]中的exceptions数组默认空数组随后返回一个Program节点访问器。Program(node)在遍历到程序根节点时通过sourceCode.getScope(node)拿到全局作用域global scope遍历其中的每个变量。checkVariable(variable)核心筛选逻辑——只有满足variable.writeable false即该变量是只读的且名字不在exceptions白名单中的变量才会被进一步检查随后对其全部引用执行checkReference。checkReference(reference, index, references)对每个引用若满足reference.init false不是变量声明初始化且reference.isWrite()是一个写引用则报告错误nativeReassign消息为Read-only global {{name}} should not be modified.。需要注意checkReference中有一个处理解构赋值的细节解构赋值可能为同一个标识符产生多个写引用因此通过index 0 || references[index - 1].identifier ! identifier去重避免对同一标识符重复报告。这套机制意味着规则并不需要硬编码内置对象清单而是完全依赖 scope manager 对变量writeable状态的判定——无论该状态来自语言内置全局、/*global*/配置注释还是配置文件中的globals设置规则都能统一覆盖。这正是它自动识别成百上千个内置全局的能力来源。测试用例印证在 tests/lib/rules/no-native-reassign.js 中可以看到规则的完整行为边界变量声明不会被误报string hello world;、var string;是合法代码——因为普通变量的writeable不为false内置对象赋值报错String hello world;、Array 1;均产生nativeReassign错误自增/自减也是写操作String;同样报错印证isWrite()会把/--视为写引用解构赋值默认值会被检测({Object 0, String 0} {});ES6产生两个错误只读全局的任意赋值形式都报错/*global b*/ b 1;、function f() { b 1; }配合globals: { b: false }都会被拦截。错误示例以下代码会触发no-native-reassign报告。错误对内置全局赋值/*eslint no-native-reassign: error*/ Object null undefined 1错误对显式声明为只读的全局变量赋值/*eslint no-native-reassign: error*/ /*global window:readonly*/ window {}通过/*global window:readonly*/配置注释window被标记为只读对其赋值同样被拦截。正确示例正确对普通变量或自定义全局赋值不受影响/*eslint no-native-reassign: error*/ a 1 var b 1 b 2正确声明为可写writable的全局变量允许赋值/*eslint no-native-reassign: error*/ /*global onload:writable*/ onload function() {}选项exceptions 白名单规则接受exceptions选项用于指定一组允许被重新赋值的内置对象名{ rules: { no-native-reassign: [error, {exceptions: [Object]}] } }配置后Object 0;不再报错tests/lib/rules/no-native-reassign.js 中的合法用例正是{ code: Object 0;, options: [{ exceptions: [Object] }] }。从源码 lib/rules/no-native-reassign.js 的 schema 定义可见exceptions必须是字符串数组且uniqueItems: true不允许重复项并且additionalProperties: false——也就是说除了exceptions之外不接受任何其他配置属性。与全局变量配置体系的配合规则检测能力依赖 ESLint 的全局变量声明机制完整的声明方式见 docs/src/use/configure/language-options.md 的 Specify Globals 一节主要有两种途径方式一源码内配置注释/* global var1, var2 */ // 声明两个全局变量 /* global var1:writable, var2:writable */ // 声明并允许写入其中:readonly标记只读:writable标记可写。基于历史原因布尔值false与字符串readable等价于readonly布尔值true与字符串writeable等价于writable但这些旧写法已不推荐使用。方式二配置文件flat config// eslint.config.js import { defineConfig } from eslint/config; export default defineConfig([ { languageOptions: { globals: { var1: writable, var2: readonly, }, }, }, ]);这样var1允许被覆盖var2则被禁止覆盖配合no-native-reassign即可对自定义只读全局形成保护。另外languageOptions.globals支持设置为off来禁用某个全局例如Promise: off。对于浏览器、Node 等环境的预置全局集合可以借助globals包如globals.browser按环境批量启用测试用例中onload 0配合globals.browser合法、top 0同样配合globals.browser非法的对照正是环境全局集与只读状态协同工作的直接体现。与相关规则的协作no-undefno-native-reassign历史上曾作为no-undef的一部分被拆分出来见 docs/src/use/migrating-to-3.0.0.md。no-undef负责报告未定义变量的使用而no-native-reassign负责报告对只读全局的覆写两者职责互补no-undef文档明确建议若同时想禁止这类赋值参见 no-global-assign。no-extend-native禁止扩展原生对象如给Object.prototype添加属性与本规则分别从改引用与改原型两个角度保护内置对象。no-redeclare与no-shadow分别防止重复声明变量与变量遮蔽与只读全局保护共同构成全局命名空间的多重防线。规则已弃用迁移到 no-global-assign重要提示no-native-reassign从 ESLint v3.3.0 起已被标记为弃用deprecated理由是规则更名Renamed rule官方替换规则为no-global-assign并计划在 v11.0.0 移除见 docs/src/_data/rules_meta.json 与 docs/src/_data/rules.json 中的deprecated元数据。在新项目中应直接使用no-global-assign。对比两份实现 lib/rules/no-native-reassign.js 与 lib/rules/no-global-assign.js可以发现两者逻辑几乎完全一致同样的Program→checkVariable→checkReference结构区别仅在于规则 ID 与消息 ID 不同nativeReassignvsglobalShouldNotBeModifiedno-global-assign使用defaultOptions: [{ exceptions: [] }]声明默认选项代码更简洁no-global-assign被标记为recommended: true推荐开启而no-native-reassign为recommended: false且frozen: true标记不再演进。迁移时只需把配置中的规则名替换并保持相同的exceptions配置即可{ rules: { no-global-assign: [error, {exceptions: [Object]}] } }对应规则文档见 docs/src/rules/no-global-assign.md其测试集 tests/lib/rules/no-global-assign.js 覆盖了与旧规则完全一致的合法/非法用例包括解构默认值、自增自减、CommonJS 下的require、配置注释与languageOptions.globals两种声明方式等场景。何时不使用此规则如果你正在有意识地覆盖某个原生对象例如在 polyfill 或测试桩mock场景中替换Object、Array等内置对象则应关闭该规则或通过exceptions选项显式放行这些名字。此时建议在配置中显式注明原因避免后续维护者误解。小结no-native-reassign是 ESLint 保护运行时全局命名空间的经典规则它不维护硬编码清单而是借助 scope manager 对全局变量writeable状态的跟踪配合isWrite()写引用检测精准拦截对只读全局的一切修改形式赋值、自增自减、解构默认值。理解它的实现与配置也就理解了其继任者no-global-assign的底层机制——在迁移到后者后同样可以利用exceptions、/*global*/注释与languageOptions.globals构建完整的全局变量防护体系。【免费下载链接】eslintFind and fix problems in your JavaScript code.项目地址: https://gitcode.com/GitHub_Trending/es/eslint创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
上一篇/下一篇内容由系统自动关联 返回资讯列表 →