ESLint new-cap 规则完全指南:强制构造函数命名以大写字母开头
【免费下载链接】eslintFind and fix problems in your JavaScript code.项目地址: https://gitcode.com/GitHub_Trending/es/eslint
new-cap是 ESLint 内置的一条风格建议型(suggestion)规则,用于强制 JavaScript 构造函数名以大写字母开头,同时约束大写的函数只能作为构造函数使用。它帮助团队在执行new调用时一眼识别构造语义,避免因命名不规范导致的阅读误判与潜在new遗漏。读完本文你将掌握new-cap的全部 7 个配置项、内置豁免标识符机制、正则例外模式的实际用法,以及该规则在 ESLint 源码中的完整判定流程。
规则背景:为什么构造函数要大写
JavaScript 中new操作符会创建一个特定类型对象的新实例,而该类型由构造函数表示。构造函数本质上仍是普通函数,唯一的区分特征是调用时是否使用了new。原生 JavaScript 函数习惯以大写字母开头,以区分哪些函数应作为构造函数使用,许多风格指南也建议沿用这一约定,从而更容易识别构造调用:
const friend = new Person();new-cap规则正是基于这一命名约定而设计。需要特别说明的是,这条规则在 ESLint 中默认为关闭状态(recommended: false),且不可自动修复、不提供建议(fixable: false、hasSuggestions: false),属于纯检查型规则,这一点可以在 docs/src/_data/rules.json 的规则元数据中确认。
规则详情与内置豁免标识符
new-cap要求构造函数名以大写字母开头。某些内置标识符不受此规则约束,这些内置标识符在源码中定义于CAPS_ALLOWED常量,见 lib/rules/new-cap.js:
ArrayBooleanDateErrorFunctionNumberObjectRegExpStringSymbolBigInt
内置标识符豁免的底层实现有两处:在newIsCap方向(new调用必须大写),CAPS_ALLOWED仅作为capIsNew方向的默认豁免;而在capIsNew方向(大写函数必须配合new),源码会将CAPS_ALLOWED无条件并入豁免集合,见 lib/rules/new-cap.js。这意味着Boolean(arg)、Object(null)这类以函数方式(不带new)调用内置构造器的代码是合法的——它们属于类型转换而非构造,这一行为在测试用例var x = Boolean(42)、var x = Date.UTC(2000, 0)中均有覆盖,见 tests/lib/rules/new-cap.js。
规则默认配置下的正确代码示例:
/*eslint new-cap: "error"*/ function foo(arg) { return Boolean(arg); }Boolean(arg)之所以正确,是因为Boolean位于内置豁免列表,即便没有使用new也不会触发upper报错。
选项总览
该规则接受一个对象选项,完整定义见源码的schema与defaultOptions,见 lib/rules/new-cap.js:
| 选项 | 类型 | 默认值 | 作用 |
|---|---|---|---|
newIsCap | boolean | true | 要求所有new操作符必须调用大写开头的函数 |
capIsNew | boolean | true | 要求所有大写开头的函数必须配合new操作符调用 |
newIsCapExceptions | string[] | [] | 允许指定的小写开头函数名配合new调用 |
newIsCapExceptionPattern | string | 无 | 允许匹配指定正则的小写开头函数名配合new调用 |
capIsNewExceptions | string[] | [] | 允许指定的大写开头函数名不带new调用 |
capIsNewExceptionPattern | string | 无 | 允许匹配指定正则的大写开头函数名不带new调用 |
properties | boolean | true | 是否检查对象属性(如person.acquaintance)的大小写 |
从源码看,该对象的additionalProperties: false,传入未定义的键会直接导致配置校验失败,因此配置时务必使用上述精确键名。
newIsCap:new调用必须大写
默认配置{ "newIsCap": true }下,new调用小写开头的函数会触发lower消息("A constructor name should not start with a lowercase letter.")。
错误代码:
/*eslint new-cap: ["error", { "newIsCap": true }]*/ const friend = new person();正确代码:
/*eslint new-cap: ["error", { "newIsCap": true }]*/ const friend = new Person();当设置为{ "newIsCap": false }时,规则完全关闭对new调用的大写检查,小写构造函数同样合法:
/*eslint new-cap: ["error", { "newIsCap": false }]*/ const friend = new person();注意:newIsCap为false时,源码中对应的NewExpression监听器根本不会被注册(见 lib/rules/new-cap.js),即该方向的检查被整体跳过,而不是仅仅放行小写名称。
capIsNew:大写函数必须配合new
默认配置{ "capIsNew": true }下,以普通调用(不带new)方式使用大写开头的函数会触发upper消息("A function with a name starting with an uppercase letter should only be used as a constructor.")。
错误代码:
/*eslint new-cap: ["error", { "capIsNew": true }]*/ const colleague = Person();正确代码:
/*eslint new-cap: ["error", { "capIsNew": true }]*/ const colleague = new Person();当设置为{ "capIsNew": false }时,允许大写函数不带new调用:
/*eslint new-cap: ["error", { "capIsNew": false }]*/ const colleague = Person();对应地,capIsNew为false时源码不会注册CallExpression监听器(见 lib/rules/new-cap.js)。同理,capIsNew为false时测试中还放行了bar.Foo(42)、Foo.bar(42)等各类成员调用。
newIsCapExceptions:放行指定小写构造函数
当第三方库或既有代码中存在必须用new调用的小写构造函数时,可通过newIsCapExceptions精确放行:
/*eslint new-cap: ["error", { "newIsCapExceptions": ["events"] }]*/ const events = require('events'); const emitter = new events();这里events是 Node.js 模块,其构造函数约定为小写命名,放行后new events()不再报错。源码将该配置构造为Set以支持 O(1) 查找(见 lib/rules/new-cap.js)。
newIsCapExceptionPattern:按正则放行小写构造函数
当需要放行的是一类符合模式的名称而非枚举时,使用正则表达式。正则会被编译为带u标志的RegExp对象(见 lib/rules/new-cap.js),匹配目标是调用表达式中 callee 的源码文本。
放行person命名空间下的小写构造:
/*eslint new-cap: ["error", { "newIsCapExceptionPattern": "^person\\.." }]*/ const friend = new person.acquaintance(); const bestFriend = new person.friend();放行以.bar结尾的属性:
/*eslint new-cap: ["error", { "newIsCapExceptionPattern": "\\.bar$" }]*/ const friend = new person.bar();注意正则的匹配对象是node.callee的源码文本(sourceCode.getText(node.callee)),见 lib/rules/new-cap.js,因此^person\..匹配的是person.acquaintance这类完整表达式。测试用例newIsCapExceptionPattern: "^foo\\.."放行new foo.bar(42)正是这一机制的验证。
capIsNewExceptions:放行指定大写函数不带new
当某些大写开头的函数本身是普通函数而非构造函数时,可通过capIsNewExceptions放行其普通调用:
/*eslint new-cap: ["error", { "capIsNewExceptions": ["Person"] }]*/ function foo(arg) { return Person(arg); }源码中capIsNewExceptions会与CAPS_ALLOWED合并构造为集合(见 lib/rules/new-cap.js)。从测试用例可以看到两个值得注意的细节:
- 只放行属性名不够:
Foo.Bar(42)配合capIsNewExceptions: ["Foo"]仍然报错,必须写全名["Foo.Bar"]才能放行(见 tests/lib/rules/new-cap.js); - 匹配同时支持集合成员与源码文本两种形式,
allowedNames.has(calleeName) || allowedNames.has(sourceText)(见 lib/rules/new-cap.js)。
capIsNewExceptionPattern:按正则放行大写普通调用
放行person命名空间下的大写普通函数:
/*eslint new-cap: ["error", { "capIsNewExceptionPattern": "^person\\.." }]*/ const friend = person.Acquaintance(); const bestFriend = person.Friend();放行以.Bar结尾的属性:
/*eslint new-cap: ["error", { "capIsNewExceptionPattern": "\\.Bar$" }]*/ foo.Bar();放行以Foo开头的名称(注意会同时放行Foo、Foobar以及成员访问Foo.Bar):
/*eslint new-cap: ["error", { "capIsNewExceptionPattern": "^Foo" }]*/ const x = Foo(42); const y = Foobar(42); const z = Foo.Bar(42);对应测试用例还确认了正则的排他性:Bar.Foo(42)配合capIsNewExceptionPattern: "^Foo\\.."依然会报upper错误(见 tests/lib/rules/new-cap.js),说明模式只匹配模式本身描述的形状。
properties:是否检查对象属性
new与调用不仅作用于裸标识符,也可能作用于对象属性。默认{ "properties": true }会检查属性形式的大小写——即最后一个属性名(callee 的最后一段)需要遵循大小写约定。
错误代码:
/*eslint new-cap: ["error", { "properties": true }]*/ const friend = new person.acquaintance();正确代码:
/*eslint new-cap: ["error", { "properties": true }]*/ const friend = new person.Acquaintance();当设置为{ "properties": false }时,跳过对对象属性的检查:
/*eslint new-cap: ["error", { "properties": false }]*/ const friend = new person.acquaintance();源码中skipProperties = !config.properties,当 callee 是MemberExpression且skipProperties为真时直接放行(见 lib/rules/new-cap.js)。属性名的提取依赖astUtils.getStaticPropertyName,该方法支持标识符属性、字符串字面量属性与计算属性名(见 lib/rules/utils/ast-utils.js),因此new a.b['Constructor']()、new b[\foo`]()` 等形态也能被正确识别——这些用例都在测试中覆盖(见 tests/lib/rules/new-cap.js)。
源码级判定流程剖析
new-cap的检查核心分为"名称提取 → 大小写判定 → 豁免判断"三步,全部集中在 lib/rules/new-cap.js 中,这里拆解其实现要点:
1. 名称提取(extractNameFromExpression):若 callee 是裸标识符(Identifier),直接取名字;否则通过astUtils.getStaticPropertyName取静态属性名,取不到则返回空字符串(见 lib/rules/new-cap.js)。空名称(如new function(){}、new o[1]()这类数字索引)不会触发检查。
2. 大小写判定(getCap):取首字符并比较其toLowerCase()与toUpperCase(),分为三种状态(见 lib/rules/new-cap.js):
non-alpha:首字符无大小写变体(如_、$、数字、非字母符号),不检查;lower:小写开头,配合newIsCap检查;upper:大写开头,配合capIsNew检查。
因此new _、new $、new Σ(希腊字母 Sigma)都是合法代码。同时注意希腊字母 φ 属于小写(有对应大写变体),new φ会被报为lower错误,测试中专门覆盖了这一点(见 tests/lib/rules/new-cap.js)。
3. 豁免判断(isCapAllowed):依次检查集合成员、正则模式、对象属性开关,最后是Date.UTC特例——当 callee 是MemberExpression且属性名为UTC、对象为Date时放行(见 lib/rules/new-cap.js)。这就是测试中Date.UTC(2000, 0)合法的原因;而裸调用UTC()或a.Date.UTC()依然报错(见 tests/lib/rules/new-cap.js)。
4. 报错定位(report):若 callee 是成员表达式,报错位置指向属性段而非整个表达式,使错误定位更精准(见 lib/rules/new-cap.js)。
5. 可选链支持:规则通过astUtils.skipChainExpression(见 lib/rules/utils/ast-utils.js)剥开ChainExpression,因此foo?.Bar()、new (foo?.bar)()等可选链写法也能被正确检查,相关用例需在ecmaVersion: 2020下运行(见 tests/lib/rules/new-cap.js)。
6. 内置对象方法不豁免:new toString()、new constructor()、new valueOf()等对象原型方法默认会被报为lower错误,必须显式加入newIsCapExceptions才能放行(见 tests/lib/rules/new-cap.js),这提示团队在使用类 jQuery 风格的小写构造 API 时需要主动配置豁免。
配置方式与完整示例
在 flat config 中,可通过rules字段配置该规则,例如在 eslint.config.js 中:
export default [ { rules: { "new-cap": ["error", { newIsCap: true, capIsNew: true, newIsCapExceptions: [], newIsCapExceptionPattern: "^person\\.", capIsNewExceptions: ["Immutable"], capIsNewExceptionPattern: "\\.Bar$", properties: true }] } } ];在传统.eslintrc风格中则写为:
{ "rules": { "new-cap": ["error", { "newIsCapExceptions": ["events"] }] } }配置为"off"可以整体关闭;也可仅关闭某一方向,例如"new-cap": ["error", { "capIsNew": false }]表示只保留new必须大写这一约束,而允许大写函数作为普通函数调用。
什么时候不使用它
如果你的代码约定不要求构造函数大写,或不要求大写函数只能作为构造函数使用,请关闭该规则。典型场景包括:
- 项目采用小写风格命名的构造函数(如某些第三方库或函数式编程风格);
- 项目大量依赖必须通过普通调用触发的大写 API(此时可先用
capIsNew: false或异常模式定向放行,而非全局关闭); - 团队已有更严格的命名规范,或使用 TypeScript 的
new类型约束来保障构造语义。
总结
new-cap通过newIsCap与capIsNew双向约束,配合两个"名称集合"与两个"正则模式"的豁免机制,以及properties开关,为构造函数命名约定提供了细粒度的控制能力。结合源码(lib/rules/new-cap.js)、内置豁免列表与完整测试(tests/lib/rules/new-cap.js)来看,它正确处理了内置构造器、成员表达式、计算属性名、可选链、非字母开头标识符等边界情况,是落实 JavaScript 构造语义命名规范的基础工具之一。若你的风格指南还要求强制使用new括号(new Foo()而非new Foo),可搭配 new-parens 规则使用。
【免费下载链接】eslintFind and fix problems in your JavaScript code.项目地址: https://gitcode.com/GitHub_Trending/es/eslint
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考