前端最佳实践¶
📚 章节目标¶
本章节将全面介绍前端开发的各种最佳实践,包括代码规范、设计模式、性能优化等,帮助学习者掌握前端开发的核心方法。
学习目标¶
- 理解前端最佳实践的核心概念
- 掌握代码规范和约定
- 掌握常用设计模式
- 掌握性能优化技巧
- 理解可访问性最佳实践
- 掌握前端开发最佳实践
📝 代码规范¶
1. 命名规范¶
JavaScript
// 变量命名 - 驼峰命名法
const userName = 'John';
const isLoggedIn = true;
const maxCount = 100;
// 常量命名 - 全大写,下划线分隔
const API_URL = 'https://api.example.com';
const MAX_RETRY_COUNT = 3;
const DEFAULT_TIMEOUT = 5000;
// 函数命名 - 驼峰命名法,动词开头
function getUserById(id) {}
function calculateTotal(items) {}
function validateEmail(email) {}
// 类命名 - 驼峰命名法,首字母大写
class UserService {}
class UserRepository {}
class UserValidator {}
// 组件命名 - 驼峰命名法,首字母大写
function UserProfile() {}
function TodoList() {}
function SearchInput() {}
// 文件命名 - 驼峰命名法
// UserProfile.js
// TodoList.js
// SearchInput.js
// CSS类命名 - 短横线分隔
.user-profile {}
.todo-list {}
.search-input {}
// CSS变量命名 - 短横线分隔
:root {
--primary-color: #007bff;
--font-size-base: 16px;
--spacing-unit: 8px;
}
2. 代码格式化¶
JavaScript
// 使用Prettier格式化代码
// .prettierrc.js
module.exports = {
semi: true,
singleQuote: true,
tabWidth: 2,
trailingComma: 'es5',
printWidth: 80,
arrowParens: 'always',
endOfLine: 'lf',
};
// 不好的格式
const obj={name:"John",age:30};
function add(a,b){return a+b;}
// 好的格式
const obj = {
name: 'John',
age: 30,
};
function add(a, b) {
return a + b;
}
3. 代码注释¶
JavaScript
// 单行注释 - 解释为什么,而不是是什么
// 使用缓存避免重复计算
const cachedValue = calculateExpensiveValue();
// 多行注释 - 解释复杂的逻辑
/**
* 计算用户的折扣价格
* @param {number} price - 原始价格
* @param {Object} discount - 折扣对象
* @param {string} discount.type - 折扣类型 ('percentage' | 'fixed')
* @param {number} discount.value - 折扣值
* @returns {number} - 折扣后的价格
*/
function calculateDiscount(price, discount) {
if (discount.type === 'percentage') {
return price * (1 - discount.value / 100);
} else if (discount.type === 'fixed') {
return price - discount.value;
}
return price;
}
// TODO注释 - 标记待办事项
// TODO: 实现用户认证功能
// FIXME: 修复这个bug
// HACK: 临时解决方案
🎨 设计模式¶
1. 单例模式¶
JavaScript
// 单例模式 - 确保只有一个实例
class Singleton {
static instance = null;
constructor() {
if (Singleton.instance) {
return Singleton.instance;
}
Singleton.instance = this;
}
static getInstance() {
if (!Singleton.instance) {
Singleton.instance = new Singleton();
}
return Singleton.instance;
}
}
// 使用
const instance1 = Singleton.getInstance();
const instance2 = Singleton.getInstance();
console.log(instance1 === instance2); // true
2. 工厂模式¶
JavaScript
// 工厂模式 - 创建对象的接口
class ButtonFactory {
static createButton(type) {
switch (type) {
case 'primary':
return new PrimaryButton();
case 'secondary':
return new SecondaryButton();
case 'danger':
return new DangerButton();
default:
return new DefaultButton();
}
}
}
class PrimaryButton {
render() {
return <button className="btn btn-primary">Primary</button>;
}
}
class SecondaryButton {
render() {
return <button className="btn btn-secondary">Secondary</button>;
}
}
// 使用
const primaryButton = ButtonFactory.createButton('primary');
const secondaryButton = ButtonFactory.createButton('secondary');
3. 观察者模式¶
JavaScript
// 观察者模式 - 一对多依赖
class EventEmitter {
constructor() {
this.events = {};
}
on(event, callback) {
if (!this.events[event]) {
this.events[event] = [];
}
this.events[event].push(callback);
}
emit(event, data) {
if (this.events[event]) {
this.events[event].forEach(callback => callback(data));
}
}
off(event, callback) {
if (this.events[event]) {
this.events[event] = this.events[event].filter(cb => cb !== callback); // map转换每个元素;filter筛选;reduce累积
}
}
}
// 使用
const emitter = new EventEmitter();
emitter.on('user:login', (user) => {
console.log('User logged in:', user);
});
emitter.emit('user:login', { name: 'John' });
4. 策略模式¶
JavaScript
// 策略模式 - 定义算法族,分别封装
class DiscountStrategy {
calculate(price) {
throw new Error('Must implement calculate method');
}
}
class PercentageDiscount extends DiscountStrategy {
constructor(percentage) {
super();
this.percentage = percentage;
}
calculate(price) {
return price * (1 - this.percentage / 100);
}
}
class FixedDiscount extends DiscountStrategy {
constructor(amount) {
super();
this.amount = amount;
}
calculate(price) {
return price - this.amount;
}
}
// 使用
const percentageDiscount = new PercentageDiscount(10);
const fixedDiscount = new FixedDiscount(5);
console.log(percentageDiscount.calculate(100)); // 90
console.log(fixedDiscount.calculate(100)); // 95
⚡ 性能优化¶
1. 代码优化¶
JavaScript
// 避免不必要的渲染
// 不好的做法
function ExpensiveComponent({ data }) {
const processedData = processData(data);
return <div>{processedData}</div>;
}
// 好的做法
function ExpensiveComponent({ data }) {
const processedData = useMemo(() => processData(data), [data]);
return <div>{processedData}</div>;
}
// 避免内联函数
// 不好的做法
function ParentComponent() {
const [count, setCount] = useState(0); // 解构赋值:从对象/数组提取值
return (
<div>
<button onClick={() => setCount(count + 1)}>Increment</button>
<ChildComponent onClick={() => console.log('clicked')} />
</div>
);
}
// 好的做法
function ParentComponent() {
const [count, setCount] = useState(0);
const increment = useCallback(() => {
setCount(prev => prev + 1);
}, []);
const handleClick = useCallback(() => {
console.log('clicked');
}, []);
return (
<div>
<button onClick={increment}>Increment</button>
<ChildComponent onClick={handleClick} />
</div>
);
}
2. 资源优化¶
JavaScript
// 图片优化
// 使用合适的格式
<img src="image.webp" alt="Description" />
// 使用响应式图片
<img
src="image-small.jpg"
srcset="
image-small.jpg 400w,
image-medium.jpg 800w,
image-large.jpg 1200w
"
sizes="(max-width: 600px) 400px, 800px"
alt="Description"
/>
// 懒加载图片
<img
src="placeholder.jpg"
data-src="actual-image.jpg"
loading="lazy"
alt="Description"
/>
// 字体优化
// 使用font-display
@font-face {
font-family: 'CustomFont';
src: url('font.woff2') format('woff2');
font-display: swap;
}
// 预加载关键字体
<link
rel="preload"
href="/fonts/main.woff2"
as="font"
type="font/woff2"
crossorigin
/>
3. 网络优化¶
JavaScript
// 代码分割
// 路由级代码分割
const Home = lazy(() => import('./pages/Home'));
const About = lazy(() => import('./pages/About'));
// 组件级代码分割
const HeavyComponent = lazy(() => import('./HeavyComponent'));
// 预加载资源
<link rel="preload" href="/styles/main.css" as="style" />
<link rel="preload" href="/scripts/main.js" as="script" />
<link rel="preload" href="/fonts/main.woff2" as="font" />
// 预连接到重要域名
<link rel="preconnect" href="https://api.example.com" />
<link rel="dns-prefetch" href="https://cdn.example.com" />
♿ 可访问性¶
1. 语义化HTML¶
HTML
<!-- 不好的做法 -->
<div class="header">Header</div>
<div class="nav">Navigation</div>
<div class="main">Main Content</div>
<div class="footer">Footer</div>
<!-- 好的做法 -->
<header>Header</header>
<nav>Navigation</nav>
<main>Main Content</main>
<footer>Footer</footer>
2. ARIA属性¶
HTML
<!-- 按钮可访问性 -->
<button aria-label="Close dialog" onclick="closeDialog()">
×
</button>
<!-- 表单可访问性 -->
<label for="username">Username</label>
<input
id="username"
type="text"
aria-required="true"
aria-describedby="username-help"
/>
<small id="username-help">Enter your username</small>
<!-- 图标可访问性 -->
<button aria-label="Search">
<svg aria-hidden="true">...</svg>
</button>
3. 键盘导航¶
JavaScript
// 键盘导航
function handleKeyDown(event) {
switch (event.key) {
case 'Enter':
case ' ':
handleClick();
break;
case 'Escape':
handleClose();
break;
case 'ArrowUp':
handlePrevious();
break;
case 'ArrowDown':
handleNext();
break;
}
}
// 焦点管理
function Modal({ isOpen, onClose }) {
const modalRef = useRef(null);
useEffect(() => {
if (isOpen && modalRef.current) {
modalRef.current.focus();
}
}, [isOpen]);
return (
isOpen && (
<div
ref={modalRef}
tabIndex={-1}
onKeyDown={handleKeyDown}
role="dialog"
aria-modal="true"
>
<button onClick={onClose}>Close</button>
</div>
)
);
}
📝 练习题¶
1. 基础题¶
题目1:实现单例模式
JavaScript
// 实现单例模式
class Singleton {
// 实现单例逻辑
}
// 使用示例
const instance1 = Singleton.getInstance();
const instance2 = Singleton.getInstance();
console.log(instance1 === instance2); // true
2. 进阶题¶
题目2:实现观察者模式
JavaScript
// 实现观察者模式
class EventEmitter {
// 实现事件监听和触发
}
// 使用示例
const emitter = new EventEmitter(); // const不可重新赋值;let块级作用域变量
emitter.on('event', (data) => console.log(data)); // 箭头函数:简洁的函数语法
emitter.emit('event', { message: 'Hello' });
3. 面试题¶
题目3:解释前端性能优化的策略
JavaScript
// 答案要点:
// 1. 代码优化
// - 避免不必要的渲染
// - 使用useMemo和useCallback
// - 代码分割和懒加载
// 2. 资源优化
// - 图片优化(格式、尺寸、懒加载)
// - 字体优化(font-display、预加载)
// - 资源压缩和缓存
// 3. 网络优化
// - 使用CDN
// - 启用HTTP/2
// - 预加载和预连接
// 4. 渲染优化
// - 虚拟列表
// - 防抖和节流
// - 避免同步布局
🎯 本章总结¶
本章节全面介绍了前端开发的各种最佳实践,包括代码规范、设计模式、性能优化、可访问性等。关键要点:
- 代码规范:掌握命名规范、代码格式化、代码注释
- 设计模式:掌握单例、工厂、观察者、策略等设计模式
- 性能优化:掌握代码优化、资源优化、网络优化
- 可访问性:掌握语义化HTML、ARIA属性、键盘导航
- 最佳实践:理解前端开发的各种最佳实践
下一步将深入学习前端面试准备。