` 统一数组与字符串的索引访问)
eslint-plugin-unicornprefer-at规则实战用.at()统一数组与字符串的索引访问【免费下载链接】eslint-plugin-unicornMore than 300 powerful ESLint rules项目地址: https://gitcode.com/GitHub_Trending/es/eslint-plugin-unicorn本篇技术指南围绕 eslint-plugin-unicorn一个提供 300 条强大 ESLint 规则的插件中的prefer-at规则展开系统讲解它如何将数组、字符串上的负索引访问、charAt()、单字符substring()以及「取最后一个元素」等反模式统一改写为语义更清晰的.at()。读完本文你将掌握该规则默认检查的全部模式、两个核心配置项checkAllIndexAccess、getLastElementFunctions的用法、安全例外规则以及规则底层 AST 修复逻辑的源码实现。规则概览它在检查什么prefer-at规则规则文档、规则源码的核心目标是凡是通过索引取值的写法优先改用 ES2022 的.at()方法包括Array#at()用于数组索引访问String#at()用于字符串索引访问TypedArray#at()用于类型化数组String#charAt()的替换场景。规则类型为suggestion同时支持--fix自动修复meta.fixable: code和编辑器手动建议修复hasSuggestions: true见 rules/prefer-at.js。在插件索引文件 rules/index.js 中以prefer-at名称导出。该规则默认在插件的recommended与unopinionated两套配置中启用meta.docs.recommended标记为unopinionated。这意味着它只会在与既有代码风格冲突最小的情况下触发默认仅检查负索引适合直接加入团队的推荐配置。默认检查的 5 类反模式1. 数组负索引访问array[array.length - n]这是最常见的写法。默认规则会检查形如xxx[xxx.length - n]n 为正数的负索引访问并自动重写为.at(-n)// ❌ const foo array[array.length - 1]; const foo array[array.length - 5]; // ✅ const foo array.at(-1); const foo array.at(-5);从源码看该逻辑监听MemberExpression节点rules/prefer-at.js通过共享工具 getNegativeIndexLengthNode 识别length - n结构。该工具只接受BinaryExpression且operator -、右侧为字面量正数并要求左侧确实是对应对象的length通过isLengthOf校验它还支持嵌套的BinaryExpression如array.length - 1 - 1对括号包裹(( array.length )) - 1也能处理。自动修复时规则会先移除length节点removeLengthNode再把[替换为.at(、把]替换为)同时处理可选链array?.[array.length - 1]会修复为array?.at(-1)以及foo[foo.length - 1]中多余空格。2.String#charAt()负索引string.charAt(string.length - n)// ❌ const foo string.charAt(string.length - 5); // ✅ const foo string.at(-5);规则监听CallExpressionrules/prefer-at.js只匹配方法名为charAt、恰好一个参数、且非可选调用的调用。当参数是length - n结构时报告string-char-at-negative并给出建议修复将charAt替换为at、移除length节点。3.String#substring()取单字符string.substring(index, index 1)// ❌ const foo string.substring(index, index 1); // ✅ const foo string.at(index);这是该规则最有特色的检测项通过共享工具 getSubstringSingleCharacterIndex 识别取单个字符的substring()调用两个参数都是非负整数字面量且差值为 1substring(0, 1)、substring(1, 2)、substring(2, 1)注意substring会自动交换参数因此顺序无关形如substring(index, index 1)、substring(index, 1 index)形如substring(index - 1, index)。若替换区间内存在注释如string.substring(index, /* comment */ index 1)规则会照常报告但降级为不包含 fix 的纯建议见 rules/prefer-at.js避免误删注释。4.slice()取首元素array.slice(-1)[0]/.pop()/.shift()// ❌ const foo array.slice(-1)[0]; const foo array.slice(-1).pop(); const foo array.slice(-1).shift(); // ✅ const foo array.at(-1);规则对slice(-1)之后紧跟[0]、.shift()、.pop()的取首元素模式进行修复rules/prefer-at.js。核心判定函数 getSliceCallResult 要求slice的第一个参数是负整数字面量slice(-1, -8)这类两参数形式仅当endIndex startIndex 1时才安全修复部分场景如array.slice(-9).shift()这类参数不满足严格条件的情况只给出建议修复而非自动修复以规避slice与at对越界行为不一致如shift()返回undefined而.at()也会返回undefined但某些边界参数下语义存在差异的风险。当模式位于赋值左侧LHS如array.slice(-1)[0] 1时规则会跳过避免把可写位置改成只读的方法调用。5. 取最后一个元素的函数调用_.last()等// ❌ const foo lodash.last(array); // ✅ const foo array.at(-1);_.last()、lodash.last()、underscore.last()三个函数始终被检查硬编码在 lodashLastFunctions报告get-last-function并自动修复为.at(-1)。修复时规则会妥善处理括号例如_.last(new Array)会修复为(new Array).at(-1)以及分号问题当上一行语句未加分号时会在替换结果前补;见 rules/prefer-at.js。规则刻意放过的安全例外prefer-at的设计哲学是宁可不查也不误报源码与测试test/prefer-at.js都覆盖了大量例外场景// ✅ 正索引访问默认不检查除非开启 checkAllIndexAccess const foo array[100]; // ✅ 赋值左侧不检查.at() 只读不可作为赋值目标 array[array.length - 1] foo; // ✅ DOM 集合不检查children / childNodes / querySelectorAll() 等 // 浏览器中这些集合尚不能保证支持 .at() const foo element.children[element.children.length - 1]; // ✅ arguments 不检查类数组对象没有 Array#at() function foo() { return arguments[arguments.length - 1]; }DOM 例外通过 isDomCollectionReceiver 实现childNodes、children属性以及getElementsByClassName、querySelectorAll等方法会被忽略源码注释表明待浏览器 NodeList/HTMLCollection 稳定支持.at()后可移除。同理对象字面量、非字符串字面量、箭头函数、普通函数、类表达式等明显不是数组的接收者也一律跳过isObviouslyNonArrayReceiver。此外prefer-at与同为 unicorn 的prefer-negative-index规则形成互补像array.at(array.length - 1)这种写法本规则不处理但 prefer-negative-index 会将其改写为array.at(-1)。配置项详解checkAllIndexAccess类型boolean默认值false默认只检查负索引设为true后非负整数字面量索引也会被检查并改写为.at(){ unicorn/prefer-at: [ error, { checkAllIndexAccess: true } ] }/* eslint unicorn/prefer-at: [error, {checkAllIndexAccess: true}] */ const foo bar[10]; // Fails, will fix to bar.at(10) const foo bar[unknownProperty]; // Passes const foo string.charAt(unknownIndex); // Fails开启后规则通过 getStaticValueIfNoSideEffects 静态求值索引只接受无副作用的、可静态确定的安全非负整数见 rules/prefer-at.jscharAt()则不关心索引具体值只要调用形态匹配就会检查测试 test/prefer-at.js 中string.charAt(9)、string.charAt(unknown)、string.charAt(1.5)均为 invalid。注意let声明的绑定不会被解析为确定的对象因此let object {1: 1, a: 2}; object[1]仍会被报告测试注释明确说明了这一点。getLastElementFunctions类型string[]用于登记自定义的取最后一个元素函数支持点路径写法utils.lastElement{ unicorn/prefer-at: [ error, { getLastElementFunctions: [ getLast, utils.lastElement ] } ] }/* eslint unicorn/prefer-at: [error, {getLastElementFunctions: [utils.lastElement]}] */ // ❌ const foo utils.lastElement(bar); // ✅ const foo bar.at(-1);schema 中要求该数组元素唯一uniqueItems: true且规则在匹配时通过 isNodeMatchesNameOrPath 支持任意层级的属性路径与大小写精确匹配测试中甚至验证了 utils.lastOne 这种带空白的配置也能被正确 trim 后匹配见 test/prefer-at.js。规则之间的协作关系与unicorn/prefer-string-slice互补prefer-at处理单字符的substring()模式而prefer-string-slice负责一般性的字符串切片场景两者覆盖范围不重叠见 prefer-string-slice 文档。与unicorn/prefer-negative-index互补array.at(array.length - 1)这类已用.at()但仍是负索引表达式的写法由 prefer-negative-index 规则 继续优化为array.at(-1)。源码级的检测与修复流程整条规则的执行可以概括为 5 个独立的CallExpression/MemberExpression监听分支rules/prefer-at.js每条分支对应一组messageId与修复策略场景messageId修复方式数组负索引访问negative-index自动 fix数组非负索引开启选项后index自动 fixcharAt(length - n)string-char-at-negative建议修复charAt(...)普通调用开启选项后string-char-at建议修复substring单字符string-substring建议修复区间含注释时无 fixslice(-1)[0]/pop()/shift()slice满足安全条件自动 fix否则建议取最后元素的函数调用get-last-function自动 fix规则的defaultOptions为[{getLastElementFunctions: [], checkAllIndexAccess: false}]与文档默认值保持一致rules/prefer-at.js配置 schema 禁止额外未知属性additionalProperties: false。对于.at()的浏览器与运行环境兼容性ES2022 已将其加入标准库Node.js 16.6 及现代浏览器均支持团队在引入该规则前建议根据目标运行环境确认.at()可用或依赖 polyfill这也是插件在 DOM 集合与arguments场景主动避让的原因所在。【免费下载链接】eslint-plugin-unicornMore than 300 powerful ESLint rules项目地址: https://gitcode.com/GitHub_Trending/es/eslint-plugin-unicorn创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考