高质量前端代码
好的前端代码应该具备哪些特征
问题
什么样的前端代码是好的?如何评判代码质量?
解答
好的前端代码具备以下特征:可读、可维护、可测试、高性能、健壮。
1. 可读性
差的代码:
// 命名模糊,逻辑混乱
function fn(a, b, c) {
return a.filter(x => x.d > b && x.e < c).map(x => ({ ...x, f: x.d * 0.8 }))
}
好的代码:
// 命名清晰,意图明确
function filterProductsByPriceRange(products, minPrice, maxPrice) {
const isInPriceRange = (product) =>
product.price >= minPrice && product.price <= maxPrice
const applyDiscount = (product) => ({
...product,
discountedPrice: product.price * 0.8
})
return products
.filter(isInPriceRange)
.map(applyDiscount)
}
2. 可维护性
差的代码:
// 高耦合,难以修改
class UserPage {
async loadData() {
const res = await fetch('/api/user')
const user = await res.json()
document.getElementById('name').innerText = user.name
document.getElementById('avatar').src = user.avatar
localStorage.setItem('user', JSON.stringify(user))
}
}
好的代码:
// 职责分离,低耦合
// api.js - 数据获取
export const fetchUser = () => fetch('/api/user').then(res => res.json())
// storage.js - 存储逻辑
export const saveUser = (user) => localStorage.setItem('user', JSON.stringify(user))
// UserPage.js - 页面逻辑
class UserPage {
constructor(api, storage, renderer) {
this.api = api
this.storage = storage
this.renderer = renderer
}
async loadData() {
const user = await this.api.fetchUser()
this.storage.saveUser(user)
this.renderer.render(user)
}
}
3. 可测试性
差的代码:
// 依赖全局状态,无法单元测试
function calculateTotal() {
const items = window.cartItems
const discount = window.userDiscount
return items.reduce((sum, item) => sum + item.price, 0) * discount
}
好的代码:
// 纯函数,易于测试
function calculateTotal(items, discount = 1) {
if (!Array.isArray(items)) return 0
const subtotal = items.reduce((sum, item) => sum + (item.price || 0), 0)
return subtotal * discount
}
// 测试用例
console.assert(calculateTotal([{ price: 100 }, { price: 200 }], 0.9) === 270)
console.assert(calculateTotal([], 1) === 0)
console.assert(calculateTotal(null) === 0)
4. 性能
差的代码:
// 每次渲染都创建新函数和新对象
function ProductList({ products }) {
return (
<ul>
{products.map(p => (
<li
key={p.id}
style={{ color: 'blue' }}
onClick={() => console.log(p.id)}
>
{p.name}
</li>
))}
</ul>
)
}
好的代码:
// 缓存函数和样式
const itemStyle = { color: 'blue' }
function ProductItem({ product, onClick }) {
return (
<li style={itemStyle} onClick={onClick}>
{product.name}
</li>
)
}
function ProductList({ products }) {
const handleClick = useCallback((id) => {
console.log(id)
}, [])
return (
<ul>
{products.map(p => (
<ProductItem
key={p.id}
product={p}
onClick={() => handleClick(p.id)}
/>
))}
</ul>
)
}
5. 健壮性
差的代码:
// 没有错误处理
async function getUserName(userId) {
const res = await fetch(`/api/users/${userId}`)
const data = await res.json()
return data.profile.name
}
好的代码:
// 完善的错误处理
async function getUserName(userId) {
if (!userId) {
throw new Error('userId is required')
}
try {
const res = await fetch(`/api/users/${userId}`)
if (!res.ok) {
throw new Error(`HTTP error: ${res.status}`)
}
const data = await res.json()
return data?.profile?.name ?? 'Unknown'
} catch (error) {
console.error('Failed to fetch user:', error)
throw error
}
}
关键点
- 命名清晰:变量、函数名能准确表达意图,不用缩写和单字母
- 职责单一:每个函数/模块只做一件事,便于复用和修改
- 纯函数优先:减少副作用,输入输出可预测,方便测试
- 防御性编程:处理边界情况、空值、异常,代码不会意外崩溃
- 适度抽象:不过早优化,不过度设计,在可读性和复用性间平衡
目录