ESLint `logical-assignment-operators` 规则全解析:用 `||=`、`=`、`??=` 简化赋值代码
ESLintlogical-assignment-operators规则全解析用||、、??简化赋值代码【免费下载链接】eslintFind and fix problems in your JavaScript code.项目地址: https://gitcode.com/GitHub_Trending/es/eslint本文是 ESLint 内置规则logical-assignment-operators的完整技术指南。该规则针对 ES2021 引入的逻辑赋值运算符||、、??既可以强制要求使用这些简写形式也可以禁止使用以保持代码风格统一。读完本文你将掌握该规则的两种字符串选项与enforceForIfStatements对象选项的完整配置方式理解它如何识别可缩短为逻辑赋值的表达式包括if语句中的等价模式并能结合仓库源码看懂其底层的引用一致性判断、求值顺序保护与 getter 安全检查机制。规则背景ES2021 逻辑赋值运算符ES2021 为逻辑运算符||、和??引入了赋值简写形式。在此之前赋值简写仅适用于、*等数学运算可参考同仓库的 operator-assignment 规则文档它列出了一张完整的、-、*等简写对照表。逻辑赋值简写的前提是赋值目标与逻辑表达式的左侧操作数引用相同。例如a a || b // 可以简写为 a || b三个逻辑赋值运算符的行为各不相同这一点与数学运算简写有本质区别简写形式等价写法语义a \|\| ba a \|\| b仅当a为 falsy 时才赋值a ba a b仅当a为 truthy 时才赋值a ?? ba a ?? b仅当a为null/undefined时才赋值由于这三个运算符都具备短路求值特性它们与operator-assignment规则所覆盖的数学运算简写行为不同因此在 operator-assignment 规则文档 中被明确排除在外交由本规则独立处理。规则详情与默认行为该规则由 lib/rules/logical-assignment-operators.js 实现规则元信息meta中声明了type: suggestion建议类规则、fixable: code可自动修复以及hasSuggestions: true同时提供手动建议。recommended: false表明它不在eslint:recommended预设中需要开发者显式启用。规则要求或禁止使用逻辑赋值运算符简写可通过以下配置控制字符串选项选项默认值行为always✅ 默认要求尽量使用逻辑赋值简写never—禁止使用逻辑赋值简写对象选项仅当字符串选项为always时可用配置项默认值行为enforceForIfStatements: false✅ 默认不检查等价的if语句enforceForIfStatements: true—检查可改写为逻辑赋值的if语句从源码的 schema 定义lib/rules/logical-assignment-operators.js可以看出选项的组合约束always模式可携带最多 1 个{ enforceForIfStatements: boolean }对象minItems: 0允许不传任何选项即纯默认配置而never模式不允许携带对象选项maxItems: 1。默认选项defaultOptions: [always]意味着即使不写配置规则也按always生效。选项always强制使用简写在always模式下规则会检查所有可以被逻辑赋值运算符缩短的表达式。例如a a || b可以缩短为a || b。针对多个操作数连续拼接的表达式规则有专门的关联性associativity处理策略形如a a || b || c的表达式默认被报告为可缩短为a || b || c但如果开发者使用括号显式定义了求值顺序例如a (a || b) || c则不会被报告——此时括号的存在意味着作者有意控制短路边界。这一行为在源码中由getLeftmostOperand函数实现lib/rules/logical-assignment-operators.js它沿着逻辑表达式的左侧不断下钻一旦发现某个左侧子表达式被括号包裹isParenthesised为真就停止下钻并保留该位置从而尊重括号表达的求值意图。always下的错误incorrect代码示例/*eslint logical-assignment-operators: [error, always]*/ a a || b a a b a a ?? b a || (a b) a (a b) a ?? (a b) a a || b || c a a b c a a ?? b ?? c除了a a || b这类赋值形式规则还覆盖a || (a b)这种逻辑表达式内嵌赋值的写法。从源码的监听器可见lib/rules/logical-assignment-operators.jsalways模式主要匹配两类节点AssignmentExpression[operator][right.typeLogicalExpression]形如foo foo || bar先通过isSameReference校验左右引用一致再检查最左操作数LogicalExpression[right.typeAssignmentExpression][right.operator]形如foo || (foo bar)此时右侧赋值必须加括号否则会被解析为(foo || foo) bar这种非法语法。always下的正确correct代码示例/*eslint logical-assignment-operators: [error, always]*/ a b a b a || b a b || c a || (b c) if (a) a b a (a || b) || c注意if (a) a b在默认配置下是正确代码因为默认enforceForIfStatements: false不检查if语句a (a || b) || c因括号明确了求值顺序而豁免。测试文件 tests/lib/rules/logical-assignment-operators.js 的 valid 用例还补充了更多不报告的情形例如a a b || c混合运算符、左操作数不一致、a (a || b) || c加括号以及a || (a || b)右操作数本身已是逻辑赋值等。选项never禁止简写never模式与always完全相反用于要求团队统一采用显式的a a || b写法禁止使用||、、??。从源码看lib/rules/logical-assignment-operators.js该模式监听所有AssignmentExpression通过astUtils.isLogicalAssignmentOperator定义于 lib/rules/utils/ast-utils.js判断运算符是否为三个逻辑赋值之一命中即报告unexpectedUnexpected logical operator assignment ({{operator}}) shorthand.。never下的错误incorrect代码示例/*eslint logical-assignment-operators: [error, never]*/ a || b a b a ?? bnever下的正确correct代码示例/*eslint logical-assignment-operators: [error, never]*/ a a || b a a b a a ?? b选项enforceForIfStatements检查等价的if语句当配置为[always, { enforceForIfStatements: true }]时规则会额外识别一组可用逻辑赋值运算符表达的if语句模式。源码中该检查由IfStatement[alternatenull]监听器完成lib/rules/logical-assignment-operators.js它要求if语句没有else分支、函数体要么是空块要么只含一条语句ifNode.consequent.body.length 1、函数体是赋值表达式语句。关键在于getExistence函数lib/rules/logical-assignment-operators.js它将if的条件表达式归类为三类存在性检查并映射到对应的赋值运算符if条件形式识别的检查对应运算符a、Boolean(a)、!!atruthy真值检查!a、!Boolean(a)falsy假值检查\|\|a null、a void 0隐式空值比较空值检查??a null \|\| a undefined显式空值比较空值检查??条件识别的背后是一组精巧的辅助判断函数isImplicitNullishComparison源码识别value null/value void 0形式的隐式空值比较且要求其中一侧是引用、另一侧是null字面量或void 0表达式isExplicitNullishComparison源码则识别value null || value undefined形式的双重严格比较——它要求两个比较操作数引用一致且null与undefined各居一侧顺序无所谓。isUndefined源码通过isReferenceToGlobalVariable确保undefined是全局变量而非被局部遮蔽的标识符——这正是测试中用const undefined 0场景验证的目的。[always, { enforceForIfStatements: true }]下的错误incorrect代码示例/*eslint logical-assignment-operators: [error, always, { enforceForIfStatements: true }]*/ if (a) a b // a b if (!a) a b // a || b if (a null) a b // a ?? b if (a null || a undefined) a b // a ?? b[always, { enforceForIfStatements: true }]下的正确correct代码示例/*eslint logical-assignment-operators: [error, always, { enforceForIfStatements: true }]*/ if (a) b c if (a 0) a b第一例中赋值目标b与条件引用a不一致无法简写第二例中a 0不属于真值/假值/空值三类可识别检查测试中if (a b) a b、if (a undefined) a b、if (a ! null) a b等也均不被报告因此保持原样。修复机制与 getter 安全保护该规则在always和never两个方向上都提供了自动修复fix与建议suggestion双重能力具体走哪条路径由createConditionalFixer源码根据安全条件决定安全时直接产出fix否则降级为suggest数组中的单条建议。安全判断的核心是cannotBeGetter源码与accessesSingleProperty源码对于标识符Identifier严格模式下或不在with块内时认为其不可能触发 getter可以安全自动修复对于成员表达式MemberExpression仅当对象是Identifier、Super、ThisExpression这些基础类型且访问的是单一属性计算属性a[b]要求b本身不是成员表达式或链式表达式时才可自动修复否则只提供建议。例如测试用例a.b a.b ?? c的output为null不自动修复但suggestions中给出了a.b ?? c的建议输出——因为属性a.b可能触发 getterESLint 保守地不直接修改代码。同理with (object) a a || b也仅产生建议。此外所有 fixer 在动手前都会检查sourceCode.getCommentsInside(...)若表达式内部存在注释则放弃自动修复见测试中a /* between */ a || b、a a || /* between */ b的output: null用例避免在注释处破坏代码结构。修复时的另一个细节是括号保护在never模式把a ?? b展开为a a ?? b时若右操作数本身是逻辑表达式??与||/不可混用fixer 会为右操作数补充括号防止语义改变。在配置文件中启用规则该规则不在eslint:recommended预设中需要显式配置。以下是在 ESLint 配置文件中的几种用法// eslint.config.jsflat config export default [ { rules: { // 默认行为强制使用简写等价于 [error, always] logical-assignment-operators: error, // 显式指定 always 检查 if 语句 logical-assignment-operators: [error, always, { enforceForIfStatements: true }], // 禁止使用逻辑赋值简写 logical-assignment-operators: [error, never], }, }, ];规则对应的语言版本要求逻辑赋值运算符属于 ES2021 语法运行环境Node.js 或转译器需支持 ES2021。测试文件 tests/lib/rules/logical-assignment-operators.js 中的RuleTester正是以ecmaVersion: 2021运行验证的个别涉及私有字段的用例如this.#prop || (this.prop value)则使用ecmaVersion: 2022单独标注。When Not To Use It何时关闭此规则使用逻辑赋值运算符简写本质上是一种风格选择。如果团队希望在具体场景中自行判断哪种写法可读性更好例如在强调尽量减少赋值副作用的代码中偏好显式写法完全可以直接关闭此规则让开发者逐例决定。如果选择启用建议结合代码审查或编辑器自动修复--fix落地以消除a a || b与a || b混用的不一致状态。由于规则自带安全机制——无法确认 getter 副作用时只给建议、不强行修改——即便在大型存量代码库中开启也相对稳妥。【免费下载链接】eslintFind and fix problems in your JavaScript code.项目地址: https://gitcode.com/GitHub_Trending/es/eslint创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考