十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

ESLint no-loss-of-precision 规则全解析:拦截 JavaScript 数字字面量的运行时精度丢失

ESLint no-loss-of-precision 规则全解析:拦截 JavaScript 数字字面量的运行时精度丢失 ESLint no-loss-of-precision 规则全解析拦截 JavaScript 数字字面量的运行时精度丢失【免费下载链接】eslintFind and fix problems in your JavaScript code.项目地址: https://gitcode.com/GitHub_Trending/es/eslint本篇指南以 ESLint 内置规则no-loss-of-precision官方规则文档为核心讲解它如何识别并阻止那些在编译期看着正确、运行期却悄悄变值的数字字面量。读完本文你将掌握 IEEE 754 双精度浮点数的精度边界、该规则覆盖的十进制/二进制/八进制/十六进制字面量判定逻辑以及它在eslint:recommended推荐配置下的实际接入方式。规则背景数字字面量为何会静默失真no-loss-of-precision是一条problem类型的规则用于禁止使用会在运行时因 64 位浮点舍入而丢失精度的数字字面量见 docs/src/rules/no-loss-of-precision.md 的引言。它不检查任何运行时计算只针对源码中直接写死的数字number literal做静态审计。JavaScript 中所有Number都按 IEEE 754 标准的双精度double-precision浮点数存储其尾数部分仅能精确表示约 1516 位十进制有效数字。一旦程序员在字面量中写下超出该精度的额外数字这些数字在转换为Number类型时就会被舍入丢弃导致程序行为与源码意图不一致——而这种错误通常不会抛出任何异常属于最隐蔽的 bug 类型之一。在 ESLint 的规则元数据中见 docs/src/_data/rules_meta.json该规则被标记为type: problem属于确定有问题的代码错误而非风格建议recommended: true已被列入eslint:recommended推荐集任何启用推荐配置的项目默认开启dialects: [JavaScript, TypeScript]同时适用于 JavaScript 与 TypeScript 语法。规则详情精度丢失的判定原理十进制字面量的判定流程从源码实现看lib/rules/no-loss-of-precision.js规则的入口在create(context)中监听Literal节点并通过isNumber()先排除字符串、布尔值等非数值字面量create(context) { return { Literal(node) { if (isNumber(node) losesPrecision(node)) { context.report({ messageId: noLossOfPrecision, node, }); } }, }; }核心判断函数losesPrecision按进制分流十进制走baseTenLosesPrecision其余走notBaseTenLosesPrecision。十进制路径的判定思路非常精妙lib/rules/no-loss-of-precision.js规范化源文字面量先调用getRaw()剔除数字分隔符_如9_007_199_254_740_993→9007199254740993再用convertNumberToScientificNotation()把字面量转换为科学计数法对象ScientificNotation其中coefficient保存去除前导零与尾随零后的有效数字字符串magnitude保存数量级十进制指数。特殊情况处理若数值为 0则直接校验规范化后的系数是否全为 0若字面量的有效数字超过 100 位requestedPrecision 100无需转换即可判定为精度丢失。回读比对用node.value.toPrecision(requestedPrecision)把运行时已存储的数值按用户请求的精度重新格式化为字符串再同样规范化如果用户想要的数与实际存储的数在数量级或有效数字系数上不一致即判定该字面量会丢失精度。换句话说规则不是凭位数一刀切12300000000000000000000000有 26 位却合法而是精确对比源码想表达的数值与运行时真实能表示的数值只有当两者真正不同才报告。非十进制字面量的判定流程对于二进制0b/0B、八进制0o/0O以及旧式0前缀、十六进制0x/0X字面量notBaseTenLosesPrecision采用更直接的方法lib/rules/no-loss-of-precision.js将去除分隔符后的原始字符串按对应进制toString(base)与node.value的实际值做回读比较若源码写出的进制表示与运行时真实值的进制表示不一致说明发生了精度丢失。isBaseTen()lib/rules/no-loss-of-precision.js负责识别进制检查原始文本是否以0x/0X/0b/0B/0o/0O前缀开头或是否符合旧式八进制形态^0[0-7]$。不正确的代码示例以下代码会被no-loss-of-precision以error级别报告规则消息为noLossOfPrecision文案是This number literal will lose precision at runtime.见 lib/rules/no-loss-of-precision.js/*eslint no-loss-of-precision: error*/ const a 9007199254740993 const b 5123000000000000000000000000001 const c 1230000000000000000000000.0 const d .1230000000000000000000000 const e 0X20000000000001 const f 0X2_000000000_0001;逐个解读这些用例均有对应测试佐证见 tests/lib/rules/no-loss-of-precision.jsa 9007199254740993这是经典的Number.MAX_SAFE_INTEGER9007199254740991 2超过安全整数范围后相邻整数已无法区分b 512300000000000000000000000000131 位有效数字远超双精度容量且末尾的1会被舍入吞掉c 1230000000000000000000000.0、d .1230000000000000000000000整数与小数部分均因有效位数过长而失真e 0X20000000000001、f 0X2_000000000_0001十六进制字面量同样会丢失精度且支持带数字分隔符的写法_需要 ES2021 及以上的语法环境。测试中还覆盖了更多形态的非法用例tests/lib/rules/no-loss-of-precision.js例如带分隔符的90_0719925_4740.9_93e3、指数形式9.007199254740993e15、9007199254740.993e3、2e999、下溢到 0 的1e-350与1e-324以及二进制0b100000000000000000000000000000000000000000000000000001、八进制0o400000000000000001等非十进制用例。正确的代码示例以下写法均不会触发该规则/*eslint no-loss-of-precision: error*/ const a 12345 const b 123.456 const c 123e34 const d 12300000000000000000000000 const e 0x1FFFFFFFFFFFFF const f 9007199254740991 const g 9007_1992547409_91要点说明a 12345、b 123.456有效数字有限双精度可精确表示c 123e34虽然数值极大但科学计数法只包含 3 位有效数字仍可精确存储d 1230000000000000000000000026 位全是后缀零尾数只需保存123与指数不损失任何有效信息这与前文b 5123...0001结尾非零形成鲜明对比e 0x1FFFFFFFFFFFFF十六进制 53 位全 1恰好是双精度尾数能容纳的极限对应十进制9007199254740991f 9007199254740991Number.MAX_SAFE_INTEGER本身g 9007_1992547409_91数字分隔符只是书写形式不影响规则判定getRaw()会先剔除_。测试用例还确认了以下边界情况均为合法tests/lib/rules/no-loss-of-precision.js各种指数形态123.0e34、123e-34、-12.3e-34、9.00e2、9.0000000000e10回归自 eslint 议题 #19957 的修复极小值5e-324双精度最小正非零次正规数、0.00000000000000000000000123零的各种写法0、0.0、0.、-0、0e5以及带大量尾随零的123.0000000000000000000000旧式八进制形态019.5、0195、00195、0008、0377777777777777777非数值字面量true、abc、null、undefined、对象与数组字面量、9007199254740993字符串不会参与数值精度判定带分隔符的合法写法12_34_56、0b111_111_...、0x1FFF_FFFF_FFF_FFF等。配置方式Options 与推荐集接入该规则没有配置项no-loss-of-precision的meta.schema为空数组见 lib/rules/no-loss-of-precision.js即不接收任何选项无法通过参数放宽或收紧判定阈值。规则行为由实现内部固定有效数字超过 100 位一律报错其余情况严格比对用户意图与实际存储值。单独启用该规则可在扁平配置flat config中直接写入// eslint.config.js export default [ { rules: { no-loss-of-precision: error, }, }, ];或使用传统的eslintrc风格{ rules: { no-loss-of-precision: error } }已纳入 eslint:recommended由于recommended: true见 docs/src/_data/rules_meta.json只要你的配置扩展了eslint:recommended该规则就默认以error级别生效无需显式声明。这意味着在绝大多数标准 ESLint 项目中这类精度丢失字面量会直接在npx eslint或编辑器集成中亮起错误提示。源码视角规则如何做到既精准又不误报深入实现可以发现几个值得称道的设计lib/rules/no-loss-of-precision.js科学计数法抽象ScientificNotation类lib/rules/no-loss-of-precision.js用系数 数量级二元组统一表达整数与浮点normalizeInteger/normalizeFloatlib/rules/no-loss-of-precision.js负责剥离前导零、尾随零并计算数量级从而把12300000000000000000000000和123e25归一到同一表示。不依赖经验阈值除 100 位有效数字的兜底外判定完全基于toPrecision()回读比对因此不会误伤位数多但恰好可精确表示的字面量。进制全覆盖isBaseTen、notBaseTenLosesPrecision配合parseInt与toString(base)覆盖了二进制、八进制新旧两式、十六进制全部字面量形态。与解析器解耦losesPrecision(node)只消费 ASTLiteral节点的value与raw字段因此天然兼容 TypeScript测试中通过typescript-eslint/parser单独验证了 TS 场景见 tests/lib/rules/no-loss-of-precision.js。规则的注册入口位于 lib/rules/index.js采用懒加载方式() require(./no-loss-of-precision)引入避免在仅启用少量规则时拖慢启动。文档站点的规则元数据与版本信息7.1.0起收录可在 docs/src/_data/rule_versions.json 与 docs/src/_data/rules_meta.json 中查阅。实践建议大整数改用BigInt当业务确实需要超过Number.MAX_SAFE_INTEGER9007199254740991的整数时应使用9007199254740993n这类BigInt字面量而不是依赖会失真的普通数字字面量。关注有效数字而非位数判定标准是有效数字末尾补零通常安全末尾带非零有效位则危险——1.0000000000000000000000123这类夹心零同样会触发报告。保持默认推荐配置既然该规则无需选项且已进eslint:recommended直接沿用推荐集即可获得静态防护无需额外维护。警惕科学计数法形态9.007199254740993e15、2e999溢出为Infinity边界、1e-324与1e-350下溢为 0等指数写法也会被捕获说明规则不仅处理看着就很长的数字。【免费下载链接】eslintFind and fix problems in your JavaScript code.项目地址: https://gitcode.com/GitHub_Trending/es/eslint创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表