别这么做(除非你想要糟糕的前端代码)
前端代码很容易变得杂乱无章。
在这篇文章中,如果你想让前端代码保持整洁且易于维护,我将向你展示需要避免的 17 件事。
让我们开始吧👇
错误 #1:使用过多全局变量
全局变量在应用的任何地方都可以访问,这使得它们存在风险。
如果你在某个随机的地方修改了一个全局变量,可能会无意中破坏其他地方的功能,这调试起来简直是噩梦。
它们还会让测试变得更加困难,因为函数的行为可能会根据全局状态而改变。
请使用函数参数或作用域内的变量来代替。
❌ Bad:
let userRole = 'guest';
function canEditPost() {
return userRole === 'admin';
}
userRole = 'admin'; // 意外地改变了应用程序的行为
✅ Better:
function canEditPost(userRole) {
return userRole === 'admin';
}
const role = 'admin';
canEditPost(role);
错误 #2:糟糕的变量名和函数名
使用像 x
、data
或 handleStuff
这样含糊不清的名称会拖慢每个人的速度。
读者(包括未来的你)将需要猜测每个东西的作用 —— 更糟糕的是,还得四处滚动代码去查找。
一个很好的经验法则是:作用域越大,名称就应该越具描述性。
短循环?用 i
没问题。
作用域较长?使用能完整说明情况的名称。
❌ Bad:
function d(a, b) {
return a - b;
}
const x = d(100, 50);
✅ Better:
function calculateDiscount(originalPrice, discountAmount) {
return originalPrice - discountAmount;
}
const finalPrice = calculateDiscount(100, 50);
错误 #3:“万能”函数
这些函数试图在一个地方完成所有事情 —— 验证输入、更新用户界面、获取数据、处理错误等。
结果呢?函数变得冗长、杂乱,测试和调试起来十分痛苦。
相反,应该将逻辑拆分成更小、更专注的函数。
这样做提高了代码的可读性,使编写单元测试变得更容易,还能帮助你在其他地方复用逻辑。
❌ Bad:
function handleFormSubmit(event) {
event.preventDefault();
const name = event.target.name.value;
const email = event.target.email.value;
if (!name || !email.includes("@")) {
alert("Invalid form");
return;
}
setLoading(true);
fetch("/api/submit", {
method: "POST",
body: JSON.stringify({ name, email }),
})
.then(res => res.json())
.then(data => {
setUser(data.user);
navigate("/dashboard");
})
.catch(() => {
alert("Something went wrong");
})
.finally(() => setLoading(false));
}
✅ Better:
function handleFormSubmit(event) {
event.preventDefault();
const formData = getFormData(event);
if (!isValidForm(formData)) {
alert("Invalid form");
return;
}
submitForm(formData);
}
function getFormData(event) {
return {
name: event.target.name.value,
email: event.target.email.value,
};
}
function isValidForm({ name, email }) {
return name && email.includes("@");
}
async function submitForm(data) {
try {
setLoading(true);
const response = await fetch("/api/submit", {
method: "POST",
body: JSON.stringify(data),
});
const result = await response.json();
setUser(result.user);
navigate("/dashboard");
} catch (e) {
alert("Something went wrong");
} finally {
setLoading(false);
}
}
错误 #4:带有多个同类型参数的函数
当一个函数有多个相同类型的参数(如布尔值或字符串)时,很容易将它们混淆。
相反,传递一个带有命名键的对象。
这样一来,每个值的用途就很清晰了,而且你也无需跳转到函数定义处去理解发生了什么。
❌ Bad:
createUser("Alice", true, false, true);
✅ Better:
createUser({ name: "Alice", isAdmin: true, isVerified: false, isActive: true });
错误 #5:未清理资源
每当你添加事件监听器、创建定时器、设置超时函数,或者在 React 中使用 useEffect
时,一旦这些资源不再需要,就应该清理它们。
如果你不这样做,可能会导致内存泄漏、堆叠的事件监听器或幽灵网络请求。
对于长时间运行的前端应用(如仪表盘或管理面板),这些问题可能会显著影响性能,甚至导致整个应用崩溃。
❌ Bad (React):
useEffect(() => { window.addEventListener('resize', handleResize); }, []);
✅ Better:
useEffect(() => {
window.addEventListener('resize', handleResize);
return () => window.removeEventListener('resize', handleResize);
}, []);
错误 #6:无单位的变量
如果一个值有单位(如毫秒、像素或兆字节),请在变量名中包含该单位。
否则,其他开发者(或者未来的你)将不得不猜测这个数字的含义。
❌ Bad:
const timeout = 3000;
✅ Better:
const timeoutMs = 3000;
错误 #7:条件语句嵌套超过 3 层
当你的逻辑嵌套超过 2 或 3 层时,代码会变得难以阅读和理解,尤其是当你有很多 if/else
块时。
相反,尝试**“扁平化”你的代码**:
- 提前返回
- 反转条件
- 将逻辑拆分成更小的函数
这样可以使每个代码块更易于阅读和调试。
❌ Bad:
if (user) {
if (user.isAdmin) {
if (user.hasAccess) {
// do stuff
}
}
}
✅ Better:
if (!user || !user.isAdmin || !user.hasAccess) return;
// do stuff
错误 #8:在代码中硬编码 URL 或配置
像 URL、API 密钥或特定环境配置这类内容进行硬编码是个陷阱。
一旦这些值发生变化,你就得在整个代码库中四处查找修改。
相反,应将配置值存储在常量或环境变量中,然后在需要的地方导入使用。
这样你就能避免出现错误、数据不同步的问题,还能节省大量的时间。
❌ Bad:
fetch('https://api.example.com/posts');
✅ Better:
const API_BASE_URL = process.env.API_BASE_URL;
fetch(`${API_BASE_URL}/posts`);
错误 #9:保留无用代码 “以防万一”
我们都做过这样的事 —— 注释掉一些代码,然后就把它留在那里 “以防万一”。
但事实是:99% 的情况下,没人会用到这些代码 😅。而且也没人想在滚动代码时看到它们。
❌ Bad:
// old validation logic (maybe needed later)
// function validateInput(input) { ... }
✅ 更好的做法:直接删除它。
错误 #10:庞大的 “utils” 文件
经典的 utils.js
文件一开始往往很单纯,然后慢慢地就变成了各种随机函数的大杂烩。
不知不觉间,它就有几百行代码了,让人无从下手。
相反,应将工具函数放在使用它们的代码附近。
或者,将它们拆分成专注特定功能的文件,比如 arrayUtils.js
、dateUtils.js
等等。
❌ Bad:
// utils.js
export function doStuff() {}
✅ Better:
// listUtils.js (next to List component)
export function getVisibleItems(items, filter) {
return items.filter(item => item.visible && item.category === filter);
}
错误 #11:忽略错误
如果你的代码可能会抛出错误,不要直接忽略它。
被忽略的错误调试起来就像噩梦一般,尤其是在生产环境中。
即使只是简单地使用 console.error
也能节省数小时的猜测时间。
而且,如果用户受到影响,在用户界面中显示提示,让他们知道出了问题(而不是显示空白屏幕)。
❌ Bad:
try {
riskyFunction();
} catch (e) {
// nothing
}
✅ Better:
try {
riskyFunction();
} catch (e) {
console.error("Error in riskyFunction:", e);
showToast("TODO: Useful error message + actions");
}
错误 #12:一个巨大的文件
当所有内容 —— 组件、逻辑、样式和状态 —— 都包含在一个文件中时,这个文件会迅速膨胀。
最终你会得到一个超过 800 行代码的“滚动地狱”🔥。
相反,你应该:
- 拆分内容。
- 将相关代码分组到不同的文件夹中,并为每个文件赋予明确的职责。
这样做可以降低认知负担,并让新开发人员的入职变得更加容易。
❌ Bad:
// App.js — 1000+ lines of code
✅ Better: Split it up into folders:
/components
/context
/pages
错误 #13:未使用代码检查工具
像 ESLint 这样的代码检查工具能在问题进入生产环境 之前 就发现它们,从简单的 bug 到 useEffect
中缺失的 React 依赖项都能检测到。
它们还能帮助团队统一代码风格。
请确保你阅读并处理这些警告:不要到处都加上 // eslint-disable
哦 😉。
❌ Bad:
useEffect(() => {
fetchData();
}, []); // missing fetchData in deps
✅ 更好的做法:使用 ESLint + React hooks 插件。它会发出如下警告:
React Hook useEffect 缺少依赖项:'fetchData'。
错误 #14:混乱的文件夹结构
你的项目文件夹不应像个杂物抽屉。
当文件随机散落时,很难找到所需内容,而且在扩展应用时,这种困难会加剧。
相反,应使用基于功能或领域的结构。
将相关文件分组,这样新开发人员就能快速了解各项内容的用途。
❌ Bad:
/src
App.js
helpers.js
styles.css
randomStuff.js
✅ Better:
/src
/components
/services
App.js
错误 #15:为显而易见的代码添加注释
你无需解释 let count = 0
是什么意思。
相信你的读者 😉。
如果有代码让人困惑,试着简化逻辑或者使用更清晰的命名。
注释应该解释为什么要这样做,而不是解释某行代码的作用。
注释应该解释 为什么 要这样做,而不是解释某行代码 做了什么。
❌ Bad:
// Set count to 0
let count = 0;
✅ Better:
let itemCount = 0;
错误 #16:对怪异逻辑未添加注释
有时你需要添加一个变通方案或支持遗留情况。
这没问题 —— 但要 解释 原因。
如果没有注释,你的队友(或者未来的你)将会浪费时间去试图理解 magicFix42(data)
是什么意思。
留一个简短的注释吧。你之后会感谢自己的。
❌ Bad:
const result = magicFix42(data);
✅ Better:
// Applies patch for backend bug #321. Read ticket for more context
const result = magicFix42(data);
错误 #17:重复造轮子
不要重新发明轮子。
有许多由比我们更聪明的人编写的小型可靠库。
如果你能用一个值得信赖的包解决问题,那就使用它。
🟠 Ok:
function debounce(fn, delay) {
let timer;
return function (...args) {
clearTimeout(timer);
timer = setTimeout(() => fn.apply(this, args), delay);
};
}
✅ Easier:
import { debounce} from 'lodash-es';
const debouncedFn = debounce(myFn, 300);
总结
前端代码很快就会变得杂乱无章。
避免这 17 个错误,你的代码将更易于阅读、调试和维护。
未来的你——还有你的队友——都会感谢你的。