JavaScript 变量命名规范:开发者的 camelCase 驼峰命名指南

在 JavaScript 中,变量、函数、参数和对象属性用 camelCase(小驼峰命名)来命名,例如 cartTotal、fetchOrders;类和 React 组件用 PascalCase(大驼峰命名),例如 ShoppingCart;CONSTANT_CASE 只留给在程序整个生命周期内固定不变的值,例如 MAX_RETRIES。Google 和 Airbnb 的 JavaScript 风格指南在这几点上是一致的,JavaScript 自带的内置对象也遵循同样的模式。
本指南接下来先讲 JavaScript 引擎实际强制执行的规则,再讲在此之上的各种惯例,最后讲团队之间存在分歧的边缘情况:哪些 const 值配得上大写、私有字段、缩写,以及从 API 传来的 snake_case 数据。
JavaScript 本身允许什么
语言本身的规则很简短。标识符以字母、下划线或美元符号开头,后面的字符还可以是数字。字母不限于 ASCII:MDN 自己的例子就是德语单词 Früh。名称区分大小写,所以 total 和 Total 是两个不同的变量;new、class、delete 这样的保留字不能用作变量名。
let total = 1;
let Total = 2; // a different variable
const café = "ok"; // Unicode letters are allowed
const $price = 9.99;
const _unused = null;
// const 2fast = true; // SyntaxError: can't start with a digit
// const new = 1; // SyntaxError: reserved word属性名更宽松:加上引号,任何字符串都行,headers["Content-Type"] 就是这样才能成立的。超出这些规则的一切都是惯例,这也正是值得大家事先约定的原因。
camelCase:用于变量、函数和属性
camelCase 是 JavaScript 中几乎所有命名的默认选择。给值取名词性的名字,给函数取动词性的名字,这样一行代码读起来就像一句话:
const orderCount = orders.length;
const isLoggedIn = Boolean(session);
const user = { firstName: "Ada", lastLogin: null };
function calculateShipping(order) {
// ...
}对布尔值来说,加上 is、has 或 can 前缀(isLoggedIn、hasAccess),能在别人开口问之前,就回答“什么的真或假?”这个问题。Google 的指南对布尔类型的 getter 也使用同样的前缀(isFoo、hasFoo)。
Google 的指南在名称长度上也有一条好规则:在合理范围内尽量写得有描述性,并且不要靠删字母来缩写。errorCount 和 customerId 合格;nErr 和 cstmrId 不合格。指南的例外是作用域在十行以内的变量,比如短循环里的 i,或 points.map((x) => x * 2) 中的 x。
集合、计数和事件处理函数
几种模式能让名称变得可预测。数组用复数(users),单个元素用单数,这样 for (const user of users) 读起来就很自然。查找对象以它的键来命名(usersById),数字则以它所统计的对象来命名(userCount)。在 React 中,官方文档介绍了一种常见的事件命名惯例:处理函数命名为 handle 加上事件名(handleClick),接收处理函数的 props 则以 on 加首字母大写的事件名开头(onClick、onSave)。
PascalCase:用于类、构造函数和组件
凡是用 new 构造的东西都用 PascalCase,React 当作组件来渲染的东西也一样:
class ShoppingCart {
addItem(item) {
// ...
}
}
const cart = new ShoppingCart();
function OrderSummary({ order }) {
return <section>{order.id}</section>;
}对类来说,这是惯例。对 React 来说,这是硬性要求:React 文档说组件名必须以大写字母开头,否则无法工作,因为 JSX 会把 <section> 这样的小写标签当作普通的 HTML 元素。在 TypeScript 中,接口、类型别名和枚举也同样使用 PascalCase。
内置对象就是这一切的范本。构造函数用 PascalCase(Map、Promise、Date),方法用 camelCase(Object.fromEntries、Array.prototype.flatMap),固定值则用大写(Math.PI、Number.MAX_SAFE_INTEGER)。
什么时候用 CONSTANT_CASE(以及什么时候不用)
常量最容易引起混乱,因为 const 并不意味着“常量”。它只是阻止变量被重新赋值;它指向的数组或对象仍然可以改变。两大风格指南都把大写留给更严格的情形:
- Google:CONSTANT_CASE 用于深度不可变的模块级值(和静态属性)。仅仅打算永远不修改某个对象是不够的,而函数内部声明的常量仍然用 lowerCamelCase。
- Airbnb:大写是可选的,只用于已导出、用
const声明,并且(包括嵌套属性在内)可以确信永远不会改变的值。把文件内每个const都大写是不必要的。
// Module level, never changes: capitals
export const MAX_UPLOAD_BYTES = 5 * 1024 * 1024;
export const ORDER_STATUS = Object.freeze({ PENDING: "pending", SHIPPED: "shipped" });
function visibleNames(items) {
const visible = items.filter((item) => !item.hidden); // const, but not a constant
const names = []; // const binding, mutable array
for (const item of visible) names.push(item.name);
return names;
}两份指南在类枚举对象的键上存在分歧。Google 把枚举成员写成 CONSTANT_CASE,如上例所示;Airbnb 则倾向于在大写的导出名内部使用小写的键。只要整个代码库做法一致,哪种都可以。还有一点要注意:Object.freeze 是浅层的,所以被冻结的对象里仍然可以有会改变的嵌套对象。
私有字段:用 #,而不是下划线
用前导下划线标记“私有”成员(this._count)的老习惯只是一个提示;任何人仍然可以读写这个属性。Airbnb 的指南正是出于这个原因,规定不要使用前导或尾随下划线,Google 的 TypeScript 指南也禁止把它们用作前缀和后缀。现代 JavaScript 有真正的私有字段:
class Counter {
#count = 0;
increment() {
return ++this.#count;
}
}
const counter = new Counter();
counter.increment();
counter.count; // undefined
// counter.#count // SyntaxError outside the class缩写:userId 还是 userID?
Google 的规则是把缩写当作普通单词处理:customerId、xmlHttpRequest、loadHttpUrl。Airbnb 的规则正相反:缩写要么全大写,要么全小写,如 SMSContainer 或 httpRequests。浏览器自己也拿不定主意,XMLHttpRequest、innerHTML、getElementById 和 encodeURIComponent 同处于一个平台之中。
我们会选 Google 的规则,因为它可预测,让单词边界保持清晰,并且能在各种命名风格之间干净地转换。不过一致性比选哪一种更重要。我们在 camelCase 与 PascalCase 的区别中比较了每份主要指南的缩写规则。
处理 API 返回的 snake_case 数据
由 Python、Ruby 或 SQL 数据库支撑的 API 常常返回 first_name 这样的键。不要让它们在你的代码里扩散。在数据到达的地方就重命名,用解构赋值一行就能搞定:
const response = await fetch("/api/users/42");
const { first_name: firstName, last_login: lastLogin } = await response.json();对于整个数据载荷,可以为两个方向各写一个小函数,递归地转换键名,并在你的 API 客户端里调用它;我们在把 camelCase JSON 转换为 snake_case中演示了一种写法。如果只是一次性的重命名,我们的大小写转换器一键就能把 last_login 转成 lastLogin。
用 ESLint 强制执行
ESLint 的两条核心规则涵盖了其中的大部分。camelcase 会标出名称中间的下划线,同时忽略全大写的常量以及前导或尾随的下划线。new-cap 会标出用小写名称配合 new 的写法,以及不带 new 就调用首字母大写函数的写法。
// eslint.config.js
export default [
{
rules: {
camelcase: ["error", { properties: "never" }],
"new-cap": "error",
},
},
];properties: "never" 选项会让 camelcase 不再抱怨 data.first_name 这样的 API 字段,同时仍会检查你自己声明的变量。在 TypeScript 项目中,@typescript-eslint/naming-convention 做得更进一步,允许你为每一类标识符设置允许的格式:变量、函数、类、类型参数等等。Google 规则的完整内容见 Google JavaScript Style Guide。
JavaScript 变量命名检查清单
- 变量、函数、参数、方法和属性用 camelCase。
- 类、构造函数、React 组件,以及 TypeScript 的类型、接口和枚举用 PascalCase。
- 永远不变的模块级值用 CONSTANT_CASE,而不是给每个
const都用。 - 用
#private字段,而不是下划线前缀。 - 只定一条缩写规则,并写进你们的贡献指南。
- snake_case 的 API 键名只在边界处转换一次。


