ARTICLE DETAIL

资讯详情

深耕商务建站与企业官网运营的一线实战洞察。

ESLint no-return-assign 规则详解:杜绝 return 语句中的赋值歧义

ESLint no-return-assign 规则详解:杜绝 return 语句中的赋值歧义 ESLint no-return-assign 规则详解杜绝 return 语句中的赋值歧义【免费下载链接】eslintFind and fix problems in your JavaScript code.项目地址: https://gitcode.com/GitHub_Trending/es/eslint本指南以 ESLint 内置规则no-return-assign为核心讲解为什么return语句中的赋值表达式是代码异味以及该规则如何通过except-parens与always两种模式帮你消除这种歧义。读完本文你将掌握该规则的完整配置方法、父子选项的差异、与箭头函数相关的特殊行为以及底层源码的实现原理和测试验证方式。背景return中的赋值为何危险JavaScript 的一大特点是赋值几乎可以出现在任何表达式位置。正因如此一个多写或少写的等号很容易在真正想比较时却执行了赋值这在return语句中尤为常见。例如function doSomething() { return foo bar 2; }此处return的意图难以判断可能是想返回bar 2的计算结果但为何又要把它赋给foo也可能是本意是使用比较运算符如这段代码其实是个错误。由于这种歧义的存在社区公认的最佳实践是不要在return语句中使用赋值表达式。no-return-assign规则正是为了实现这一最佳实践而存在的。该规则从 ESLint 早期版本本仓库数据 docs/src/_data/rule_versions.json 显示其引入版本为0.0.9一直保留至今属于suggestion建议类规则默认不开启recommended: false见 docs/src/_data/rules.json 与 lib/rules/no-return-assign.js。规则详情捕获范围与上报方式规则的目标是消除return语句中的赋值只要在return的返回值表达式或箭头函数的表达式体中发现赋值就会给出警告。需要注意的是规则关注的是返回值表达式本身中的赋值。若赋值出现在return之后嵌套的函数体内则不会被这条规则误伤。例如function x() { return function y() { result a * b }; // 正确赋值在嵌套函数体内不属于外层 return 的返回值 }这条规则对应的报告消息有两条定义于 lib/rules/no-return-assign.js 的meta.messagesmessageId消息文本触发场景returnAssignmentReturn statement should not contain assignment.普通函数/块体内的return返回了赋值arrowAssignmentArrow function should not return assignment.箭头函数以表达式体直接返回赋值选项配置规则接受一个字符串选项取值必须为以下两者之一对应 lib/rules/no-return-assign.js 中schema的enum: [except-parens, always]选项值含义默认值except-parens禁止赋值除非赋值被括号包裹✅ 默认always禁止一切赋值括号包裹也不行❌由于defaultOptions: [except-parens]见源码 lib/rules/no-return-assign.js 与 docs/src/_data/rules_meta.json在eslint.config.jsflat config中可以这样显式配置export default [ { files: [**/*.js], rules: { no-return-assign: error, // 使用默认 except-parens no-return-assign: [error, except-parens], // 显式写清默认值 no-return-assign: [error, always], // 最严格模式 }, }, ];选项一except-parens默认这是默认选项。它禁止在return中使用赋值除非整个赋值表达式被括号包围。括号在这里充当我是有意的显式声明告诉读者没错我就是要返回一个赋值表达式的结果。默认选项下的错误示例/*eslint no-return-assign: error*/ function doSomething() { return foo bar 2; } function doSomethingElse() { return foo 2; } const foo (a, b) a b const bar (a, b, c) (a b, c b) function doSomethingMore() { return foo bar foo 0; }以上全部违规前两者是普通函数return直接返回赋值const foo (a, b) a b是箭头函数表达式体直接返回赋值const bar (a, b, c) (a b, c b)中a b只是被逗号表达式包裹整个表达式并未被括号整体包围因此仍然违规最后一个return foo bar foo 0;中的赋值出现在逻辑表达式中也未整体加括号违规。默认选项下的正确示例/*eslint no-return-assign: error*/ function doSomething() { return foo bar 2; } function doSomethingElse() { return foo bar 2; } function doSomethingMore() { return (foo bar 2); } const foo (a, b) (a b) const bar (a, b, c) ((a b), c b) function doAnotherThing() { return (foo bar) foo 0; }正确示例的要点/是比较运算而非赋值永远合法return (foo bar 2);整个赋值表达式被括号包围合法箭头函数const foo (a, b) (a b)的表达式体整体带括号合法((a b), c b)中赋值与整个逗号表达式都被括号包围合法(foo bar) foo 0中只有赋值部分被括号包围逻辑与表达式本身不在括号内——但规则只要求赋值表达式自身被括号包裹因此合法这点与上面(a b, c b)违规形成鲜明对比。选项二alwaysalways选项禁止return语句中一切赋值括号包裹也不能豁免。所有赋值都被视为问题。always 选项下的错误示例/*eslint no-return-assign: [error, always]*/ function doSomething() { return foo bar 2; } function doSomethingElse() { return foo 2; } function doSomethingMore() { return (foo bar 2); }注意最后一条在except-parens下合法的return (foo bar 2);在always下同样违规。always 选项下的正确示例/*eslint no-return-assign: [error, always]*/ function doSomething() { return foo bar 2; } function doSomethingElse() { return foo bar 2; }在always模式下唯一安全的是比较运算。若确有先赋值再返回该值的需求应把赋值拆到return之前的语句中function doSomething() { const result bar 2; return result; }与相关规则的边界no-return-assign只关心return/ 箭头函数表达式体中的赋值若项目还需要管控其他位置的赋值歧义可在本仓库 lib/rules 中寻找配套规则no-cond-assign禁止条件判断如if、while中的赋值no-assign-ternary禁止三元表达式分支中的赋值该规则在本仓库中为实验性规则需开启实验性 flag。三者互补可以覆盖赋值表达式在常见语法位置的全部隐患。何时不使用此规则如果你希望允许在return语句中使用赋值运算符例如团队代码风格依赖return x y这种紧凑写法或某些库的回调模式需要返回赋值结果可以放心关闭此规则export default [ { rules: { no-return-assign: off, }, }, ];关闭后规则不产生任何检查也不会影响其他规则工作。源码剖析规则如何判定括号包裹与祖先链阅读 lib/rules/no-return-assign.js 的create(context)实现可以完整还原规则的判定逻辑。第一步括号豁免检查规则监听每一个AssignmentExpression节点。若选项不是except-parens即always直接跳过括号判断否则调用工具函数astUtils.isParenthesised(sourceCode, node)const always context.options[0] ! except-parens; ... AssignmentExpression(node) { if (!always astUtils.isParenthesised(sourceCode, node)) { return; } ... }isParenthesised的实现位于 lib/rules/utils/ast-utils.js它通过比较赋值表达式节点前后 token 是否为(/)并校验括号的 range 是否紧贴节点边界从而精确判定该节点是否被括号整体包裹——这正是前面只有赋值本身被括号包围才放行的机制来源。这也是为什么(result) (a * b)这种只在标识符两侧加括号的写法仍然违规括号没有包住整个赋值节点。第二步沿祖先链寻找哨兵节点跳过括号检查后规则用一个SENTINEL_TYPE正则沿祖先链向上查找const SENTINEL_TYPE /^(?:[a-zA-Z]?Statement|ArrowFunctionExpression|FunctionExpression|ClassExpression)$/u;从当前赋值节点出发逐个向上遍历父节点直到遇到第一个哨兵——即任意*Statement语句节点如ExpressionStatement、ReturnStatement或函数/类表达式。这样做的目的是定位赋值所属的最近语句边界避免跨越函数边界误报比如把内层函数体内的赋值算到外层return头上。第三步分场景上报若祖先链尽头是ReturnStatement则报returnAssignment若尽头是ArrowFunctionExpression且该赋值节点正是箭头函数表达式体parent.body currentChild则报arrowAssignment若尽头是FunctionExpression/ClassExpression或普通语句说明赋值不在return路径上不报告。这条实现路径解释了为何return foo () a返回一个箭头函数的同时对foo赋值报returnAssignment而const foo (a) (b) a b柯里化箭头函数的最内层表达式体直接返回赋值报arrowAssignment。测试验证规则行为的完整清单规则行为由 tests/lib/rules/no-return-assign.js 通过RuleTester全面覆盖测试用例与官方文档示例一一对应并补充了大量边界场景valid不报错关键用例包括function x() { return (result a * b); }默认与except-parens下合法() { return (result a * b); }与() (result a * b)块体加括号与表达式体加括号均合法const foo (a,b,c) ((a b), c)整个逗号表达式加括号合法function x() { return function y() { result a * b }; }嵌套函数体中的赋值不受外层return牵连const foo (a) (b) (a b)多层箭头函数逐层加括号合法module.exports {a: 1};顶层赋值不涉及return合法。invalid报错关键用例包括function x() { return result a * b; }→returnAssignmentfunction x() { return (result) (a * b); };→returnAssignment括号未包住整个赋值节点默认模式也报错() result a * b→arrowAssignmentreturn result || (result a * b);always下逻辑表达式中的赋值也报错return foo function(){ return (bar bar1) }→returnAssignmentreturn () a () b→arrowAssignment返回的箭头函数表达式体含赋值const foo (a) (b) a b→arrowAssignment多层箭头函数最内层未加括号。这些用例同时验证了规则对ecmaVersion: 6及以上语法箭头函数的支持以及languageOptions配置在RuleTester中的正确用法。小结no-return-assign是一条简单但高频实用的建议类规则默认except-parens模式下它要求任何出现在return/ 箭头函数表达式体中的赋值都必须用括号显式声明意图always模式则彻底禁止此类写法倒逼开发者把赋值拆分为独立语句。结合本仓库中的源码实现lib/rules/no-return-assign.js、工具函数lib/rules/utils/ast-utils.js与完整测试tests/lib/rules/no-return-assign.js你可以精确预判该规则在任意赋值形态下的判定结果并据此决定是开启、加严还是关闭它。【免费下载链接】eslintFind and fix problems in your JavaScript code.项目地址: https://gitcode.com/GitHub_Trending/es/eslint创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表
PREV
查看更多资讯
NEXT
返回资讯列表