ARTICLE DETAIL

资讯详情

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

ESLint no-underscore-dangle 规则完全指南:禁止标识符悬挂下划线及 9 大配置项详解

ESLint no-underscore-dangle 规则完全指南:禁止标识符悬挂下划线及 9 大配置项详解 ESLint no-underscore-dangle 规则完全指南禁止标识符悬挂下划线及 9 大配置项详解【免费下载链接】eslintFind and fix problems in your JavaScript code.项目地址: https://gitcode.com/GitHub_Trending/es/eslint本文是 ESLint 内置规则no-underscore-dangle的完整技术指南。该规则用于禁止 JavaScript 标识符变量名、函数名、成员名、类字段名等在开头或结尾出现悬挂下划线帮助团队统一命名约定避免以_foo、foo_这类命名模拟私有成员。读完本文你将掌握该规则的触发范围、全部 9 个配置项的作用与适用场景并能结合源码与测试理解其豁免逻辑如_与__proto__的特殊处理从而在项目中精准配置。背景悬挂下划线的历史与争议在 JavaScript 的标识符命名约定中悬挂下划线dangling underscores可能是最具争议的话题之一。所谓悬挂下划线是指出现在标识符开头或结尾的下划线例如let _foo;用悬挂下划线标记私有成员在 JavaScript 中由来已久。最早可追溯到 SpiderMonkey 引擎添加的__defineGetter__()等非标准方法。此后使用单下划线前缀如_bar成为最流行的约定之一用于表示某个成员不属于对象的公共接口。不过官方文档明确建议优先使用 ECMAScript 2022 正式引入的私有类特性private class features如#field、#method来封装私有数据与方法而不是依赖命名约定。悬挂下划线纯粹是一种约定对性能、可读性或复杂度没有任何影响即使开启了本规则它也不具备私有类特性那样的真正封装能力。规则详情它检查什么no-underscore-dangle规则禁止在标识符中出现悬挂下划线。默认情况下它检查变量声明、函数声明/表达式、成员表达式属性访问、方法定义、类字段等场景。默认不通过的代码incorrect/*eslint no-underscore-dangle: error*/ let foo_; const __proto__ {}; foo._bar();默认通过的代码correct/*eslint no-underscore-dangle: error*/ const _ require(underscore); const obj _.contains(items, item); obj.__proto__ {}; const file __filename; function foo(_bar) {}; const bar { onClick(_bar) {} }; const baz (_bar) {};注意这些默认通过示例背后各有依据_作为 underscore 库的惯用绑定名被豁免obj.__proto__ {}属于成员表达式中的__proto__特殊豁免_bar作为函数参数默认被allowFunctionParams放行。这些细节在下面的源码级豁免逻辑一节会逐一展开。规则元信息与配置入口从规则元数据docs/src/_data/rules_meta.json 与 lib/rules/no-underscore-dangle.js可以看到该规则的关键属性类型typesuggestion属于风格建议类规则不涉及可修复的安全/正确性问题是否推荐recommendedfalse未包含在eslint:recommended中需要团队显式开启是否可修复fixablefalse该规则不提供自动修复因为是否允许下划线属于约定取舍无法机械替换是否有建议hasSuggestionsfalse是否冻结frozentrue表示该规则的默认行为与选项已被冻结后续版本不会再破坏性变更消息模板messagesUnexpected dangling _ in {{identifier}}.所有违规报告都复用这一条消息并在data.identifier中携带具体的标识符名称。在 lib/rules/index.js 中注册后即可通过配置文件开启// eslint.config.jsflat config export default [ { rules: { no-underscore-dangle: error, }, }, ];Options9 个配置项总览该规则接受一个对象选项全部字段及其默认值如下配置项默认值作用allow[]允许指定标识符带悬挂下划线allowAfterThisfalse是否允许this对象的成员带悬挂下划线allowAfterSuperfalse是否允许super对象的成员带悬挂下划线allowAfterThisConstructorfalse是否允许this.constructor对象的成员带悬挂下划线enforceInMethodNamesfalse是否在方法名中强制禁止悬挂下划线enforceInClassFieldsfalse是否在 ES2022 类字段名中强制禁止悬挂下划线allowInArrayDestructuringtrue是否允许数组解构赋值的变量名带悬挂下划线allowInObjectDestructuringtrue是否允许对象解构赋值的变量名带悬挂下划线allowFunctionParamstrue是否允许函数参数名带悬挂下划线这些默认值直接定义在源码的defaultOptions中lib/rules/no-underscore-dangle.js并在create(context)开头通过context.options解构读取第 84-96 行。选项的 schema 校验位于第 38-75 行所有字段均为布尔或字符串数组类型additionalProperties: false意味着传入未列出的选项名会直接报配置错误。逐项详解与示例allow白名单放行指定标识符allow接受一个字符串数组数组中列出的标识符无论出现在哪里只要名字完全匹配即被豁免。它与单个下划线_的隐式豁免不同——allow是显式声明的白名单。/*eslint no-underscore-dangle: [error, { allow: [foo_, _bar] }]*/ let foo_; foo._bar();从源码看豁免判定在isAllowed(identifier)中实现lib/rules/no-underscore-dangle.js即allow.includes(identifier)的精确字符串匹配不会做部分匹配或模糊匹配。allowAfterThis允许this上的下划线成员默认false时this._prop这类访问会被报错。开启后/*eslint no-underscore-dangle: [error, { allowAfterThis: true }]*/ const a this.foo_; this._bar();源码中的判定位于checkForDanglingUnderscoreInMemberExpressionlib/rules/no-underscore-dangle.js当node.object.type ThisExpression且allowAfterThis为真时跳过报告。这一选项非常适合使用下划线表示实例内部状态的类库开发场景。allowAfterSuper允许super上的下划线成员与allowAfterThis对称控制super成员访问/*eslint no-underscore-dangle: [error, { allowAfterSuper: true }]*/ class Foo extends Bar { doSomething() { const a super.foo_; super._bar(); } }源码中通过node.object.type Super判断是否为super的成员访问。注意此选项只豁免super.xxx_这种形式this._prop依然会被报错——测试用例中专门验证了开启allowAfterSuper后访问this._prop仍然报错的行为tests/lib/rules/no-underscore-dangle.js。allowAfterThisConstructor允许this.constructor上的下划线成员该选项专门处理this.constructor._bar这样的链式访问。默认false时它会被报错开启后豁免/*eslint no-underscore-dangle: [error, { allowAfterThisConstructor: true }]*/ const a this.constructor.foo_; this.constructor._bar();源码中对应的判定函数是isThisConstructorReferencelib/rules/no-underscore-dangle.js它要求节点的object本身是MemberExpression属性名为constructor且其object是ThisExpression即严格匹配this.constructor形态。enforceInMethodNames强制检查方法名默认false时方法名中的下划线如_onClick、onClick_不被检查——这是为了兼容 React 生命周期钩子、事件处理器等常见下划线命名习惯。设置为true后类方法和对象字面量方法中的悬挂下划线都会报错/*eslint no-underscore-dangle: [error, { enforceInMethodNames: true }]*/ class Foo { _bar() {} } class Bar { bar_() {} } const o1 { _bar() {} }; const o2 { bar_() {} };实现上由checkForDanglingUnderscoreInMethod处理lib/rules/no-underscore-dangle.js它同时监听MethodDefinition类方法与Property且node.method为真即对象方法简写两种节点。私有方法#_bar也会被检查且报告中的标识符会带#前缀如#_bar便于区分公有与私有成员。enforceInClassFields强制检查 ES2022 类字段名与enforceInMethodNames对应该选项控制 ES2022 类字段field的检查。默认false放行开启后公有字段、带初始化器的字段、私有字段全部纳入检查/*eslint no-underscore-dangle: [error, { enforceInClassFields: true }]*/ class Foo { _bar; } class Bar { _bar () {}; } class Baz { bar_; } class Qux { #_bar; } class FooBar { #bar_; }实现位于checkForDanglingUnderscoreInClassFieldlib/rules/no-underscore-dangle.js监听PropertyDefinition节点私有字段同样在报告中显示#前缀。注意PropertyDefinition与普通对象Property是不同的 AST 节点类型因此字段检查与方法检查互不干扰——例如开启enforceInClassFields但未开启enforceInMethodNames时_field报错而_method() {}不报错。allowInArrayDestructuring数组解构中的下划线变量默认true数组解构的占位变量如const [_foo, _bar] list被放行这是为了支持常见的忽略某个数组元素惯用法。设置为false后/*eslint no-underscore-dangle: [error, { allowInArrayDestructuring: false }]*/ const [_foo, _bar] list; const [foo_, ..._qux] list; const [foo, [bar, _baz]] list;注意嵌套解构同样会被检查const [foo, [bar, _baz]] list中的内层_baz也会报错。源码中的实现技巧是在checkForDanglingUnderscoreInVariableExpressionlib/rules/no-underscore-dangle.js里通过sourceCode.getDeclaredVariables(node)拿到变量再从标识符节点向上遍历直到找到VariableDeclarator、ArrayPattern或ObjectPattern三者之一作为判定上下文据此决定是否放行。allowInObjectDestructuring对象解构中的下划线变量默认true放行对象解构中的下划线变量设为false后/*eslint no-underscore-dangle: [error, { allowInObjectDestructuring: false }]*/ const { foo, bar: _bar } collection; const { qux, xyz, _baz } collection;以下代码在该选项下依然正确注意区别/*eslint no-underscore-dangle: [error, { allowInObjectDestructuring: false }]*/ const { foo, bar, _baz: { a, b } } collection; const { qux, xyz, _baz: baz } collection;第一条中_baz是解构的源属性名右侧键而真正声明的新变量是a、b因此不违规第二条中_baz: baz把源属性_baz的值赋给新变量baz新变量名baz无下划线同样通过。测试用例也验证了这一点tests/lib/rules/no-underscore-dangle.js并覆盖了const { _foo 1 } obj、const { bar: _foo 1 } obj、..._rest等更多变体。从源码看对象解构判定依据的是标识符的parent是否为ObjectPattern且变量声明节点落在这个模式上——因为_baz: baz中_baz位于键的位置其 parent 仍是Property不会命中豁免分支却也不会触发检查检查的是声明变量的名字。allowFunctionParams函数参数中的下划线默认true放行函数参数这是非常常见的约定用_或_arg表示未使用但必须接收的参数常见于事件回调。设为false后函数声明、函数表达式、箭头函数以及带默认值、rest 形态的参数都会被检查/*eslint no-underscore-dangle: [error, { allowFunctionParams: false }]*/ function foo1 (_bar) {} function foo2 (_bar 0) {} function foo3 (..._bar) {} const foo4 function onClick (_bar) {} const foo5 function onClick (_bar 0) {} const foo6 function onClick (..._bar) {} const foo7 (_bar) {}; const foo8 (_bar 0) {}; const foo9 (..._bar) {};实现上由checkForDanglingUnderscoreInFunctionParameters完成lib/rules/no-underscore-dangle.js对每个参数若是RestElement则检查其argument若是AssignmentPattern则检查其left否则直接检查参数本身只有Identifier类型才报告因此嵌套的解构参数如function foo([_bar]) {}不会在参数检查中重复报错。源码级豁免逻辑_与__proto__理解该规则最关键的是搞清楚两个隐式豁免1. 单独的_标识符永不报错。hasDanglingUnderscorelib/rules/no-underscore-dangle.js首先判断identifier ! _因此const _ require(underscore)这类用法天然合法同时foo.bar._这种属性访问也不会报错测试用例第 28 行。在解构场景中const { foo: [_bar, _, { bar: _baz }] } ...里的_同样被豁免tests/lib/rules/no-underscore-dangle.js。2.__proto__在成员表达式中豁免但在变量声明中不豁免。这是最容易被误解的一处obj.__proto__ {}是正确代码——因为isSpecialCaseIdentifierForMemberExpressionlib/rules/no-underscore-dangle.js对成员表达式中的__proto__返回真const __proto__ {}是错误代码——因为变量表达式场景只豁免_isSpecialCaseIdentifierInVariableExpression第 144-147 行__proto__作为变量声明仍会被检查文档开头的 incorrect 示例与测试用例第 328-335 行都印证了这一点。之所以这样设计从工程角度看是合理的成员访问obj.__proto__是操作对象原型的常见合法写法而把它声明为局部变量则几乎没有正当理由。规则在真实代码中的行为边界结合测试套件 tests/lib/rules/no-underscore-dangle.js可以归纳出几条容易踩坑的行为边界命名函数与匿名函数具名函数声明的名字如function _foo() {}会被检查而匿名函数export default function() {}、(function _foo() {})不受影响但具名函数表达式内部的名字_foo是允许的测试第 31 行因为其作用域仅限函数自身。函数名与参数是两套检查checkForDanglingUnderscoreInFunctionlib/rules/no-underscore-dangle.js先检查函数声明/表达式自身的名字再调用参数检查。即便allowFunctionParams: false函数名_foo的检查仍由独立的hasDanglingUnderscore逻辑负责。allow白名单优先于一切开关例如allowFunctionParams: false配合allow: [_bar]时参数_bar被放行allowInArrayDestructuring: false配合allow: [_bar]时_bar同样被放行tests/lib/rules/no-underscore-dangle.js。源码中所有检查函数最终都统一经过!isAllowed(identifier)这道闸门。Import attributes 的键不受影响import foo from foo.json with { _type: json }等 ES2025 导入属性语法不会误报测试第 264-288 行因为这些键不是标识符声明。var foo_bar 1合法只要下划线不在开头或结尾即非悬挂如foo_bar、_之外的中间下划线一律放行——hasDanglingUnderscore只检查首尾字符。When Not To Use It何时关闭此规则如果你所在团队希望允许标识符中的悬挂下划线——例如项目依赖大量采用_前缀的第三方库风格或团队内部明确约定用下划线前缀标记内部实现——那么可以安全地关闭此规则export default [ { rules: { no-underscore-dangle: off, }, }, ];即便关闭也建议在代码评审中讨论私有成员的表达方式悬挂下划线始终只是约定无法阻止外部代码直接访问看似私有的成员真正需要封装时应优先使用 ES2022 的#private语法。总结no-underscore-dangle是一个约定型建议规则它不修复代码、不包含在推荐集、行为已冻结但通过 9 个精细的开关能够在几乎不影响惯用写法underscore 库的_、回调参数_arg、数组解构占位、__proto__成员访问的前提下统一团队标识符命名风格。实际项目中建议从默认配置开始仅按需开启enforceInMethodNames与enforceInClassFields适用于追求命名统一的新项目并为少量白名单标识符配置allow。深入阅读规则实现 lib/rules/no-underscore-dangle.js 与测试 tests/lib/rules/no-underscore-dangle.js可以完整掌握其判定边界更多规则元信息可参考 docs/src/_data/rules_meta.json。【免费下载链接】eslintFind and fix problems in your JavaScript code.项目地址: https://gitcode.com/GitHub_Trending/es/eslint创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表