4、JavaScript规范:变量命名、函数设计原则、条件与循环优化、错误处理规范
JavaScript 这门语言,灵活是真灵活,坑也是真不少。我带过不少团队,发现代码质量的分水岭往往不在用了什么框架,而在于最基础的写法习惯。今天咱们就聊聊这四个核心点,都是我在实际项目中摔过跟头才总结出来的。
4.1 变量命名:别让后来人猜谜语
我见过最离谱的变量名是什么?a、b、c,还有 data1、data2。你想想看,三个月后你自己回来看这段代码,能记得 data1 是用户列表还是订单金额吗?
命名原则其实就三条:
- 语义化:看到名字就知道它存什么。比如
userList比list好,isLoading比flag好。 - 统一风格:变量用驼峰
camelCase,常量用大写MAX_COUNT,类名用帕斯卡PascalCase。 - 避免缩写:除非是业界共识(比如
i做循环索引),否则别自己造缩写。我见过有人写usrInf,猜了半天是 user information。
我个人习惯的命名对照表:
| 类型 | 推荐写法 | 不推荐写法 |
|---|---|---|
| 布尔值 | isVisible、hasPermission |
visible、permission |
| 数组 | userList、items |
userArr、data |
| 函数 | getUserById、handleClick |
get、doSomething |
| 常量 | API_BASE_URL、MAX_RETRY |
baseUrl、max |
小技巧:命名时试着读出来。如果读起来像一句话,那就是好名字。比如 user.isActive 读作「用户是活跃的」,很自然。而 user.act 读作「用户.活动」?怪怪的。
4.2 函数设计原则:一个函数只做一件事
这个原则听起来简单,做起来难。我在项目中遇到过一段代码,一个函数干了三件事:验证表单、发送请求、更新页面状态。结果后来需求变了,只想改验证逻辑,但不敢动,因为怕影响后面两件事。
函数设计的三个要点:
- 单一职责:一个函数只做一件事。如果函数名里出现了「和」字,比如
validateAndSubmit,那大概率该拆了。 - 参数不超过三个:参数多了,调用方容易搞错顺序。我建议用对象传参,比如
createUser({ name, age, email }),清晰又灵活。 - 避免副作用:函数最好只通过返回值影响外部,而不是偷偷修改全局变量。嗯,这里要注意,
Array.sort会改变原数组,很多人踩过这个坑。
// 不推荐:一个函数做太多事
function processOrder(order) {
// 验证
if (!order.id || !order.amount) throw new Error('订单不完整');
// 计算
const total = order.amount * 1.1;
// 发送
api.send(order.id, total);
// 记录日志
log('订单处理完成');
}
// 推荐:拆分成小函数
function validateOrder(order) {
if (!order.id || !order.amount) throw new Error('订单不完整');
}
function calculateTotal(amount) {
return amount * 1.1;
}
function processOrder(order) {
validateOrder(order);
const total = calculateTotal(order.amount);
api.send(order.id, total);
log('订单处理完成');
}
我曾经接手过一个项目,有个函数叫 handleEverything,里面 300 多行。改一个 bug 要花半天时间理清逻辑。后来我花了两天重构,拆成 12 个小函数,每个不超过 20 行。测试好写了,bug 也少了。
4.3 条件与循环优化:少写 if-else,多用早期返回
条件判断写不好,代码就像一团乱麻。你想想看,嵌套四五层的 if-else,读起来得多痛苦?
优化条件判断的几个套路:
- 早期返回(Early Return):把异常情况先处理掉,剩下的就是正常逻辑。说白了,就是「先排除干扰项」。
- 用对象或 Map 替代 switch:当条件分支很多时,查表比写一长串 switch 更清晰。
- 循环里别做重复计算:比如
arr.length在循环条件里每次都会计算,提前存到变量里。
// 不推荐:嵌套地狱
function getDiscount(user) {
if (user) {
if (user.isVip) {
if (user.level > 3) {
return 0.8;
} else {
return 0.9;
}
} else {
return 1;
}
} else {
return 1;
}
}
// 推荐:早期返回 + 查表
function getDiscount(user) {
if (!user) return 1;
if (!user.isVip) return 1;
const discountMap = {
1: 0.95,
2: 0.9,
3: 0.85,
4: 0.8,
};
return discountMap[user.level] || 1;
}
循环优化小贴士:如果只是遍历数组,用 for...of 或 forEach 比传统 for 循环更可读。但如果需要提前跳出循环,for 循环配合 break 还是最合适的。
4.4 错误处理规范:别让用户看到「undefined is not a function」
错误处理是 JavaScript 里最容易忽视的部分。很多人只写「快乐路径」,异常情况一概不管。结果线上出了问题,用户看到白屏,开发者一脸懵。
错误处理的三个层次:
- 防御性编程:对不确定的数据做检查。比如从 API 拿到的数据,可能字段缺失,用
?.和??操作符可以优雅处理。 - try-catch 要精准:别把整个函数包在 try-catch 里,那样会掩盖真正的 bug。只包住可能出错的代码块。
- 错误信息要有用:别只写
Error: 出错了,要带上上下文。比如Error: 获取用户列表失败,userId: 123。
// 不推荐:错误信息太模糊
try {
const data = await api.getUser(id);
render(data);
} catch (e) {
console.log('出错了');
}
// 推荐:精准捕获 + 有用信息
async function loadUser(id) {
if (!id) {
throw new Error('loadUser 需要传入有效的 id');
}
let data;
try {
data = await api.getUser(id);
} catch (e) {
// 区分网络错误和业务错误
if (e.status === 404) {
throw new Error(`用户 ${id} 不存在`);
}
throw new Error(`获取用户 ${id} 失败: ${e.message}`);
}
if (!data || !data.name) {
throw new Error(`用户 ${id} 的数据结构异常`);
}
render(data);
}
我曾经在一个支付项目里,因为没做错误处理,用户支付成功后页面卡住了。排查了半天,发现是后端返回的字段名变了,前端没做兼容。从那以后,我对所有外部数据都加了校验,宁可多写几行代码,也不能让用户看到白屏。
说白了,JavaScript 规范不是束缚,而是保护。保护你自己不被自己写的代码坑到,也保护你的队友能安心接手你的代码。这些习惯养成了,写代码会越来越顺手。