拓冰建站拓冰建站
首页 / 资讯中心 / 正文

ESLint no-var 规则详解:用 let 与 const 全面取代 var

ESLint no-var 规则详解用 let 与 const 全面取代 var【免费下载链接】eslintFind and fix problems in your JavaScript code.项目地址: https://gitcode.com/GitHub_Trending/es/eslintESLint 的no-var规则建议类规则rule_type: suggestion旨在全面禁止使用var声明变量引导开发者改用 ES6ECMAScript 6引入的let与const块级作用域声明。本文将基于本仓库eslint 项目中的 规则文档 与 规则实现源码系统讲解no-var的判定逻辑、可自动修复范围、TypeScript 场景支持以及迁移注意事项帮助你安全地把旧代码中的var批量升级为let。为什么需要 no-var函数作用域带来的经典陷阱ECMAScript 6 允许程序员使用let和const关键字创建块级作用域block scope变量而非var的函数作用域function scope。块级作用域在许多其他编程语言中很常见能帮助程序员避免一类典型错误块内声明意外覆盖外层同名变量。以规则文档给出的示例为例var count people.length; var enoughFood sandwiches.length count; if (enoughFood) { var count sandwiches.length; // accidentally overriding the count variable console.log(We have count sandwiches for everyone. Plenty for all!); } // our count variable is no longer accurate console.log(We have count people and sandwiches.length sandwiches!);由于var声明会被提升hoisting到函数作用域顶部if块内的var count与函数外层count是同一个变量第二次赋值后原始计数被永久破坏。若改用let/const块内声明会形成独立绑定外层值不受影响。no-var规则正是为了在代码层面杜绝这类隐患。Rule Details规则目标与判定标准no-var规则的目标是阻止var的使用鼓励改用const或let。从实现上看该规则在VariableDeclaration节点退出时触发检查只要node.kind var就报告错误见 lib/rules/no-var.js#L470-L485报告消息为Unexpected var, use let or const instead.见 lib/rules/no-var.js#L317-L319。在 rules/index.js 中该规则以懒加载方式注册可在 ESLint 配置中通过no-var: error、warn或off三种严重级别启用。不正确的代码示例将被报告/*eslint no-var: error*/ var x y; var CONFIG {};正确的代码示例通过检查/*eslint no-var: error*/ let x y; const CONFIG {};需要注意的是规则只要求消除var至于应该用let还是const取决于变量是否会被重新赋值——const适用于从不改变的绑定如上述CONFIG。文档中的示例以/*eslint no-var: error*/行内注释形式展示实际项目中通常将规则写入配置文件如eslint.config.js。TypeScript 场景支持no-var规则额外支持 TypeScript 类型语法。在 TypeScript 中有多种声明全局变量的方式其中只有var适用于所有场景因此本规则针对 TypeScript 的declare声明也有专门处理。不正确的 TypeScript 代码示例/*eslint no-var: error*/ declare var x: number declare namespace ns { var x: number } declare module module { var x: number }正确的 TypeScript 代码示例/*eslint no-var: error*/ declare global { declare var x: number }从源码看规则对 TypeScript 有一个专门豁免当var声明位于declare global块即TSModuleBlock的父节点是TSModuleDeclaration且global为真时直接跳过检查见 lib/rules/no-var.js#L476-L483。这是因为在declare global环境中declare var是唯一合法的全局声明方式。对应的测试用例见 tests/lib/rules/no-var.js#L600-L618也验证了declare global { var bar: car }是合法代码而declare var x、declare namespace ns { var ... }、declare module module { var ... }均会被报告并可修复为let。Options无配置项no-var规则没有选项。其schema为空数组见 lib/rules/no-var.js#L314启用时只需配置严重级别即可例如// eslint.config.js export default [ { rules: { no-var: error, }, }, ];自动修复何时可以安全地把 var 改成 letno-var是可自动修复的规则fixable: code见 lib/rules/no-var.js#L315。但var与let的语义差异远不止作用域关键字本身——var允许重声明、允许提升后提前引用、循环中共享同一实例而let禁止这一切。因此源码中的canFix()函数见 lib/rules/no-var.js#L402-L446实现了大量安全检查以下情况只报告、不修复测试覆盖见 tests/lib/rules/no-var.js1. 全局变量或变量被重声明var允许在同一作用域重复声明而let的重声明是语法错误因此当变量是全局变量isGlobal或被重声明isRedeclared即variable.defs.length 2见 lib/rules/no-var.js#L121-L123时不修复。测试用例var a, b, c; var a;与var a; if (b) { var a; }均输出null不修复但每个var都会被报告tests/lib/rules/no-var.js#L169-L198。2. 变量在声明之前被引用var的声明提升允许先使用后声明let则不行会触发暂时性死区 TDZ。源码通过hasReferenceBeforeDeclaration检查引用位置是否早于声明位置lib/rules/no-var.js#L208-L222。测试用例function test() { console.log(x); var x 1; }因此不会被修复tests/lib/rules/no-var.js#L459-L463。3. 变量被提升的函数声明在声明前调用hasUnsafeHoistedFunctionReference专门处理提升的函数声明在变量声明之前被调用、且该函数内部引用了该变量的场景lib/rules/no-var.js#L231-L272。例如function wrap() { foo(); var a 1; function foo() { console.log(a); } }不修复因为foo()调用时a还未被赋值而var a 1在foo()之前初始化时则可以修复见 tests/lib/rules/no-var.js#L562-L569。4. 变量逃逸出所在作用域isUsedFromOutsideOf检查变量是否在声明所在块之外被引用lib/rules/no-var.js#L131-L148。if (foo) { var a, b, c; } a;、for (var i 0; i 10; i) {} i;等用例均不修复tests/lib/rules/no-var.js#L191-L222因为改成let后外部引用会抛 ReferenceError。5. 声明位于 SwitchCase 节点上若修改switch的case分支中的var会触发no-case-declarations规则警告而eslint:recommended预置集包含该规则因此这类声明不修改见 lib/rules/no-var.js#L355-L361 的注释说明以及node.parent.type SwitchCase检查。测试用例switch (a) { case 0: var b 1 }不修复tests/lib/rules/no-var.js#L223-L230。6. 变量存在 TDZ 自引用var a a、var {a a} {}这类声明在初始化器中引用自身改成let会触发 TDZ 错误。hasSelfReferenceInTDZ与hasReferenceInTDZ负责检测lib/rules/no-var.js#L162-L190、lib/rules/no-var.js#L330-L337。测试用例var a a、var {a a} {}、var a b, b 1均不修复tests/lib/rules/no-var.js#L250-L294。7. 循环中被闭包引用或可能未初始化循环内var声明在所有迭代间共享同一变量实例而let每次迭代创建新实例行为差异可能不安全。源码检查isReferencedInClosure变量被更具体的函数表达式闭包引用时不修复lib/rules/no-var.js#L57-L65。用例for (var a of b) { arr.push(() a); }不修复tests/lib/rules/no-var.js#L233-L240。循环内let声明无初始化器时初始化为null而var会保留上一轮迭代的值。只有当变量是循环赋值目标isLoopAssignee如for (var a of b)或声明带初始化器时才安全转换lib/rules/no-var.js#L424-L431。用例for (let a of b) { var c; console.log(c); c hello; }不修复tests/lib/rules/no-var.js#L241-L248。值得注意的是for (var a of b)、for (var a in b)、for (var i 0; ...)这类循环头部的var是可以修复为let的见 tests/lib/rules/no-var.js#L92-L139 的output断言这也是最推荐的现代写法。8. 声明不在语句列表位置规则只修复位于语句列表中的声明。if (foo) var bar 1;这种单行声明不在块内let写法会改变作用域语义因此不修复lib/rules/no-var.js#L433-L443对应测试 tests/lib/rules/no-var.js#L322-L334。语句列表父节点集合STATEMENT_LIST_PARENTS定义于 lib/rules/utils/ast-utils.js#L50-L56包括Program、BlockStatement、StaticBlock、SwitchCase本规则额外补充了TSModuleBlock。9. 变量名为let或与 catch 参数冲突变量名为let如function foo() { var let; }时改成let let是语法错误不修复hasNameDisallowedForLetDeclarationslib/rules/no-var.js#L198-L200测试见 tests/lib/rules/no-var.js#L371-L381。var允许重用简单 catch 子句参数的名字但let不允许在 catch 块内直接声明是语法错误在嵌套块内则行为改变var赋值给 catch 参数let创建新绑定。isShadowedByCatchParameter专门检测此场景lib/rules/no-var.js#L292-L296。用例try {} catch (e) { var e 1; }不修复而try {} catch (e) { var x 1; }正常修复tests/lib/rules/no-var.js#L509-L552。10. 变量在函数表达式内部被自引用var foo (function () { foo(); })();这类在立即调用函数表达式IIFE内部自引用的场景改成let会因 TDZ 报错而不修复但普通命名函数表达式赋值如var fx function (i 0) { ... return fx(...) }可以安全修复见 tests/lib/rules/no-var.js#L383-L433。修复机制只替换关键字不动声明结构当canFix返回true时修复逻辑极其简单——找到声明节点的var关键字 token整体替换为letlib/rules/no-var.js#L453-L468fix(fixer) { const varToken sourceCode.getFirstToken(node, { filter: t t.value var, }); return canFix(node) ? fixer.replaceText(varToken, let) : null; }也就是说no-var的自动修复统一替换为let不会自作主张推断该用const。例如var foo bar, toast most;修复为let foo bar, toast most;tests/lib/rules/no-var.js#L68-L79var CONFIG {}也会被修复为let CONFIG {}是否进一步改为const由开发者自行决定可通过prefer-const规则配合处理。与相关规则的配合prefer-constno-var只负责消除var而prefer-const规则负责把从未重新赋值的let进一步升级为const两者配合可实现声明从不改变 → const否则 → let的完整现代化迁移。no-case-declarationseslint:recommended预置集tests/conf/eslint-recommended.js中的规则no-var为避免与它冲突特意不修复switchcase 分支内的var声明。prefer-arrow-callback与no-var同属 ECMAScript 6 现代化迁移规则族常一起启用。在 rule-type-list.json 的规则类型分类中no-var属于suggestion类型非 problem、非 layout表示它更多是风格与最佳实践层面的建议而非会破坏运行时行为的问题规则。When Not To Use It何时应关闭此规则在以下场景应考虑关闭或调整no-var非 ES6 环境需要支持不支持let/const的旧运行时如老旧浏览器、低版本 Node.js时应关闭此规则。存量项目渐进迁移成本过高已有 JavaScript 项目刚开始引入 ES6 时若从var到let的迁移代价过大可能不希望立即应用此规则。尤其是涉及上面列举的不修复场景重声明、提升依赖、闭包捕获等时手动改造需要逐一确认行为差异。TypeScript 的declare global场景如本文所述该场景下var是唯一合法的全局声明方式规则已自动豁免。建议的落地策略是在新代码中直接启用no-var: error对存量代码使用--fix自动修复安全部分再结合代码审查逐步处理剩余的不修复场景。总结no-var是 ES6 代码现代化中最基础也最安全的规则之一它无配置项、语义清晰、可自动修复其核心价值在于利用块级作用域从源头避免var的作用域提升与变量覆盖问题。理解其canFix中十余种只报告不修复的边界场景全局/重声明/逃逸作用域/TDZ/闭包/循环/catch 参数冲突等能帮助你在批量迁移时准确预判哪些代码需要人工介入真正做到安全、高效地把var全面替换为let与const。【免费下载链接】eslintFind and fix problems in your JavaScript code.项目地址: https://gitcode.com/GitHub_Trending/es/eslint创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门