JavaScript 代码复用性全面指南:从基础到高级模式
·
JavaScript 代码复用性全面指南:从基础到高级模式
1. 基础复用方案
1.1 函数封装
基础函数封装
// 重复代码
const result1 = array1.filter(item => item > 2).map(item => item * 2);
const result2 = array2.filter(item => item > 2).map(item => item * 2);
// 封装后
function filterAndMap(array, filterFn, mapFn) {
return array.filter(filterFn).map(mapFn);
}
const result1 = filterAndMap(array1, item => item > 2, item => item * 2);
const result2 = filterAndMap(array2, item => item > 5, item => item * 3);
高阶函数
// 创建通用的验证函数
function createValidator(rules) {
return function(data) {
return rules.every(rule => rule(data));
};
}
// 使用
const isEmail = createValidator([
data => data.includes('@'),
data => data.length > 5
]);
const isStrongPassword = createValidator([
data => data.length >= 8,
data => /[A-Z]/.test(data),
data => /[0-9]/.test(data)
]);
1.2 面向对象编程(OOP)
类继承
class Animal {
constructor(name) {
this.name = name;
}
speak() {
console.log(`${this.name} makes a noise.`);
}
}
class Dog extends Animal {
speak() {
console.log(`${this.name} barks.`);
}
}
class Cat extends Animal {
speak() {
console.log(`${this.name} meows.`);
}
}
组合优于继承
// 功能组合
const canEat = {
eat() {
console.log(`${this.name} is eating.`);
}
};
const canSleep = {
sleep() {
console.log(`${this.name} is sleeping.`);
}
};
class Animal {
constructor(name) {
this.name = name;
Object.assign(this, canEat, canSleep);
}
}
1.3 模块化
ES6 模块
// utils/math.js
export function add(a, b) {
return a + b;
}
export function multiply(a, b) {
return a * b;
}
export const PI = 3.14159;
// main.js
import { add, multiply, PI } from './utils/math.js';
通用工具模块
// domUtils.js
export const domUtils = {
// DOM 操作
$(selector) {
return document.querySelector(selector);
},
// 事件绑定
on(element, event, handler) {
element.addEventListener(event, handler);
},
// AJAX 封装
ajax(url, options = {}) {
return fetch(url, options).then(res => res.json());
}
};
// 使用
import { domUtils } from './domUtils.js';
domUtils.on(domUtils.$('#btn'), 'click', handleClick);
2. 设计模式应用
2.1 工厂模式
class User {
constructor(name, role) {
this.name = name;
this.role = role;
}
}
class UserFactory {
static createAdmin(name) {
return new User(name, 'admin');
}
static createUser(name) {
return new User(name, 'user');
}
static createGuest() {
return new User('Guest', 'guest');
}
}
// 使用
const admin = UserFactory.createAdmin('John');
const user = UserFactory.createUser('Alice');
2.2 单例模式
class Logger {
constructor() {
if (Logger.instance) {
return Logger.instance;
}
this.logs = [];
Logger.instance = this;
}
log(message) {
this.logs.push(message);
console.log(message);
}
getLogs() {
return this.logs;
}
}
// 使用 - 始终返回同一个实例
const logger1 = new Logger();
const logger2 = new Logger();
console.log(logger1 === logger2); // true
2.3 观察者模式
class EventEmitter {
constructor() {
this.events = {};
}
on(event, listener) {
if (!this.events[event]) {
this.events[event] = [];
}
this.events[event].push(listener);
}
emit(event, data) {
if (this.events[event]) {
this.events[event].forEach(listener => listener(data));
}
}
off(event, listenerToRemove) {
if (this.events[event]) {
this.events[event] = this.events[event].filter(
listener => listener !== listenerToRemove
);
}
}
}
// 使用
const emitter = new EventEmitter();
emitter.on('data', data => console.log('Received:', data));
emitter.emit('data', { message: 'Hello' });
3. 函数式编程
3.1 纯函数
// 不纯的函数
let taxRate = 0.1;
function calculateTax(amount) {
return amount * taxRate; // 依赖外部状态
}
// 纯函数
function calculateTax(amount, taxRate) {
return amount * taxRate;
}
3.2 函数柯里化
// 普通函数
function multiply(a, b, c) {
return a * b * c;
}
// 柯里化版本
function curryMultiply(a) {
return function(b) {
return function(c) {
return a * b * c;
};
};
}
// 使用
const multiplyBy2 = curryMultiply(2);
const multiplyBy2And3 = multiplyBy2(3);
const result = multiplyBy2And3(4); // 24
// 或者一行调用
curryMultiply(2)(3)(4); // 24
3.3 函数组合
// 工具函数
const compose = (...fns) => x => fns.reduceRight((v, f) => f(v), x);
const pipe = (...fns) => x => fns.reduce((v, f) => f(v), x);
// 小函数
const toUpperCase = str => str.toUpperCase();
const exclaim = str => str + '!';
const repeat = str => str.repeat(2);
// 组合使用
const dramatic = compose(exclaim, toUpperCase, repeat);
const result = dramatic('hello'); // "HELLOHELLO!"
const pipeline = pipe(repeat, toUpperCase, exclaim);
const result2 = pipeline('hello'); // "HELLOHELLO!"
4. React 生态复用方案
4.1 自定义 Hooks
// 自定义 Hook - 复用状态逻辑
function useLocalStorage(key, initialValue) {
const [storedValue, setStoredValue] = useState(() => {
try {
const item = window.localStorage.getItem(key);
return item ? JSON.parse(item) : initialValue;
} catch (error) {
return initialValue;
}
});
const setValue = value => {
try {
setStoredValue(value);
window.localStorage.setItem(key, JSON.stringify(value));
} catch (error) {
console.log(error);
}
};
return [storedValue, setValue];
}
// 使用
function Component() {
const [name, setName] = useLocalStorage('name', '');
const [theme, setTheme] = useLocalStorage('theme', 'light');
}
5. 高级参数代理技术
5.1 高阶函数参数代理
基础参数替换
// 原始函数
function fetchData(url, options) {
console.log(`Fetching from: ${url}`, options);
return fetch(url, options);
}
// 参数代理函数
function createProxyFetch(proxyConfig) {
return function(url, options = {}) {
// 替换参数
const finalUrl = proxyConfig.baseURL ?
`${proxyConfig.baseURL}${url}` : url;
const finalOptions = {
...options,
headers: {
...proxyConfig.defaultHeaders,
...options.headers
}
};
return fetchData(finalUrl, finalOptions);
};
}
// 使用
const apiFetch = createProxyFetch({
baseURL: 'https://api.example.com',
defaultHeaders: {
'Authorization': 'Bearer token123',
'Content-Type': 'application/json'
}
});
// 调用时自动添加基础URL和默认headers
apiFetch('/users'); // 实际请求: https://api.example.com/users
5.2 Proxy 对象实现参数拦截
函数参数代理
function createFunctionProxy(originalFn, paramProxy) {
return new Proxy(originalFn, {
apply(target, thisArg, args) {
// 处理参数
const processedArgs = paramProxy(args, thisArg);
return Reflect.apply(target, thisArg, processedArgs);
}
});
}
// 使用示例
function calculate(a, b, operation) {
return operation(a, b);
}
// 创建代理
const proxiedCalculate = createFunctionProxy(calculate, (args) => {
const [a, b, operation] = args;
// 参数替换逻辑
const processedA = typeof a === 'function' ? a() : a;
const processedB = typeof b === 'function' ? b() : b;
const processedOperation = operation || ((x, y) => x + y);
return [processedA, processedB, processedOperation];
});
// 测试
const result1 = proxiedCalculate(5, 3, (x, y) => x * y); // 15
const result2 = proxiedCalculate(() => 10, () => 2); // 12 (使用默认加法)
5.3 上下文参数注入
自动注入上下文参数
function createContextAwareFunction(originalFn, contextProvider) {
return function(...args) {
// 获取上下文
const context = contextProvider();
// 将上下文作为最后一个参数注入
const finalArgs = [...args, context];
return originalFn.apply(this, finalArgs);
};
}
// 原始函数
function processData(data, transform, context) {
console.log('Context:', context);
return transform(data);
}
// 创建上下文感知版本
const contextAwareProcess = createContextAwareFunction(
processData,
() => ({
userId: 123,
timestamp: Date.now(),
environment: process.env.NODE_ENV
})
);
// 使用 - 不需要显式传递context参数
const result = contextAwareProcess(
{ name: 'John' },
data => ({ ...data, processed: true })
);
5.4 条件参数替换
智能参数代理
function createSmartProxy(originalFn, rules) {
return function(...args) {
let processedArgs = [...args];
// 应用规则
rules.forEach(rule => {
if (rule.condition(processedArgs)) {
processedArgs = rule.transform(processedArgs);
}
});
return originalFn.apply(this, processedArgs);
};
}
// 使用示例
function sendNotification(message, type, options) {
console.log(`Sending ${type} notification:`, message, options);
}
// 定义参数处理规则
const notificationRules = [
{
condition: (args) => args[0] === undefined,
transform: (args) => ['Default message', ...args.slice(1)]
},
{
condition: (args) => args[1] === 'error',
transform: (args) => [args[0], 'error', { urgent: true, ...args[2] }]
},
{
condition: (args) => typeof args[0] === 'object',
transform: (args) => [args[0].text, args[0].type || 'info', args[0]]
}
];
const smartNotify = createSmartProxy(sendNotification, notificationRules);
// 测试
smartNotify(); // 使用默认消息
smartNotify('Error occurred', 'error'); // 自动添加urgent选项
smartNotify({ text: 'Hello', type: 'warning' }); // 对象参数自动解构
5.5 异步参数解析
Promise参数代理
function createAsyncParamProxy(originalFn) {
return async function(...args) {
// 解析所有Promise参数
const resolvedArgs = await Promise.all(
args.map(arg => {
if (arg instanceof Promise ||
(typeof arg === 'function' && arg.constructor.name === 'AsyncFunction')) {
return Promise.resolve(arg());
}
return Promise.resolve(arg);
})
);
return originalFn.apply(this, resolvedArgs);
};
}
// 使用示例
async function generateId() {
return Math.random().toString(36).substr(2, 9);
}
function createUser(name, id, metadata) {
return {
id,
name,
metadata,
createdAt: new Date()
};
}
const asyncCreateUser = createAsyncParamProxy(createUser);
// 使用
asyncCreateUser(
'John Doe',
generateId, // 异步函数自动执行
fetch('/api/metadata').then(res => res.json()) // Promise自动解析
).then(user => console.log(user));
5.6 配置化参数映射
声明式参数代理
function createParamMapper(originalFn, mappingConfig) {
return function(input) {
// 根据映射配置转换参数
const args = mappingConfig.map(config => {
if (config.transform) {
return config.transform(input[config.from], input);
}
return input[config.from];
});
return originalFn.apply(this, args);
};
}
// 使用示例
function connectDatabase(host, port, username, password, database) {
console.log(`Connecting to ${username}@${host}:${port}/${database}`);
}
// 定义参数映射
const dbConfigMapper = createParamMapper(connectDatabase, [
{ from: 'host' },
{ from: 'port', transform: (port) => port || 5432 },
{ from: 'user', transform: (user) => user.username },
{ from: 'user', transform: (user) => user.password },
{ from: 'name' }
]);
// 使用更简洁的参数格式
dbConfigMapper({
host: 'localhost',
user: { username: 'admin', password: 'secret' },
name: 'mydb'
// port 自动使用默认值 5432
});
5.7 组合式参数代理
可组合的代理函数
// 基础代理函数
const proxyUtils = {
// 默认值代理
withDefaults: (defaults) => (fn) => (...args) => {
const mergedArgs = { ...defaults, ...args[0] };
return fn(mergedArgs);
},
// 验证代理
withValidation: (schema) => (fn) => (args) => {
const validationResult = schema.validate(args);
if (validationResult.error) {
throw new Error(validationResult.error.message);
}
return fn(args);
},
// 日志代理
withLogging: (fn) => (args) => {
console.log('Function called with:', args);
const result = fn(args);
console.log('Function returned:', result);
return result;
}
};
// 组合使用
function processOrder(order) {
return `Processing order: ${order.id}`;
}
// 创建增强版本的函数
const enhancedProcessOrder = compose(
proxyUtils.withDefaults({ status: 'pending' }),
proxyUtils.withValidation(orderSchema),
proxyUtils.withLogging
)(processOrder);
// 使用
enhancedProcessOrder({ id: 123, amount: 100 });
6. 工具函数库与配置化
6.1 通用工具集
// utils.js
export const utils = {
// 防抖
debounce(func, wait) {
let timeout;
return function executedFunction(...args) {
const later = () => {
clearTimeout(timeout);
func(...args);
};
clearTimeout(timeout);
timeout = setTimeout(later, wait);
};
},
// 深拷贝
deepClone(obj) {
return JSON.parse(JSON.stringify(obj));
},
// 格式化和日期
formatDate(date, format = 'YYYY-MM-DD') {
// 格式化逻辑
},
// 数据验证
isValidEmail(email) {
return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
}
};
6.2 配置化和数据驱动
// 配置化的表单验证
const validationRules = {
email: {
validate: value => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value),
message: '请输入有效的邮箱地址'
},
password: {
validate: value => value.length >= 6,
message: '密码长度至少6位'
},
phone: {
validate: value => /^1[3-9]\d{9}$/.test(value),
message: '请输入有效的手机号码'
}
};
function validateField(fieldName, value) {
const rule = validationRules[fieldName];
if (!rule) return { isValid: true };
return {
isValid: rule.validate(value),
message: rule.message
};
}
7. 实际应用案例
7.1 API 请求代理
function createApiProxy(apiConfig) {
return new Proxy({}, {
get(target, endpoint) {
return (params = {}) => {
const config = apiConfig[endpoint];
if (!config) {
throw new Error(`Endpoint ${endpoint} not configured`);
}
// 参数处理和替换
const finalParams = {
...config.defaultParams,
...params
};
const url = config.url.replace(/:(\w+)/g, (_, key) =>
finalParams[key] || ''
);
return fetch(url, {
method: config.method,
headers: config.headers,
body: config.method !== 'GET' ? JSON.stringify(finalParams) : undefined
});
};
}
});
}
// 配置
const api = createApiProxy({
getUser: {
url: '/users/:id',
method: 'GET',
defaultParams: { fields: 'name,email' }
},
createUser: {
url: '/users',
method: 'POST',
headers: { 'Content-Type': 'application/json' }
}
});
// 使用
api.getUser({ id: 123, fields: 'name,email,phone' });
api.createUser({ name: 'John', email: 'john@example.com' });
8. 最佳实践总结
8.1 核心原则
- 单一职责原则:每个函数/类只做一件事
- 开放封闭原则:对扩展开放,对修改封闭
- DRY原则:不要重复自己
- 组合优于继承:优先使用组合来复用代码
- 接口隔离:创建小而专的接口
- 依赖注入:通过参数传递依赖,提高可测试性
8.2 代理模式优势
- 参数标准化:统一参数处理逻辑
- 关注点分离:参数处理与业务逻辑分离
- 可测试性:代理逻辑可以独立测试
- 可组合性:多个代理可以组合使用
- 运行时灵活性:可以根据条件动态改变参数
8.3 应用场景选择
- 简单逻辑复用:函数封装、模块化
- 复杂对象创建:工厂模式
- 全局状态管理:单例模式
- 事件驱动架构:观察者模式
- 参数处理复杂:代理模式
- React状态逻辑:自定义Hooks
- 异步操作处理:异步代理模式
8.4 选择策略
| 场景 | 推荐方案 | 优势 |
|---|---|---|
| 简单逻辑复用 | 函数封装 | 简单直接 |
| 复杂对象创建 | 工厂模式 | 创建逻辑封装 |
| 全局状态管理 | 单例模式 | 保证唯一实例 |
| 参数处理复杂 | 代理模式 | 关注点分离 |
| React状态逻辑 | 自定义Hooks | 逻辑复用 |
| 异步操作 | 异步代理 | Promise处理 |
8.5 性能考虑
- 代理开销:Proxy有一定性能开销,在性能敏感场景慎用
- 内存使用:高阶函数和闭包会增加内存占用
- 渲染优化:React中使用useCallback、useMemo避免不必要的重新渲染
8.6 代码组织建议
// 良好的代码结构
src/
├── utils/ # 纯函数工具
├── hooks/ # 自定义Hooks
├── proxies/ # 代理函数
├── factories/ # 工厂类
├── constants/ # 配置常量
└── validators/ # 验证逻辑
通过组合使用这些方案,可以显著提高JavaScript代码的复用性、可维护性和可测试性。根据具体场景选择合适的模式,避免过度设计,保持代码的简洁性和可读性。
更多推荐


所有评论(0)