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 核心原则

  1. 单一职责原则:每个函数/类只做一件事
  2. 开放封闭原则:对扩展开放,对修改封闭
  3. DRY原则:不要重复自己
  4. 组合优于继承:优先使用组合来复用代码
  5. 接口隔离:创建小而专的接口
  6. 依赖注入:通过参数传递依赖,提高可测试性

8.2 代理模式优势

  1. 参数标准化:统一参数处理逻辑
  2. 关注点分离:参数处理与业务逻辑分离
  3. 可测试性:代理逻辑可以独立测试
  4. 可组合性:多个代理可以组合使用
  5. 运行时灵活性:可以根据条件动态改变参数

8.3 应用场景选择

  • 简单逻辑复用:函数封装、模块化
  • 复杂对象创建:工厂模式
  • 全局状态管理:单例模式
  • 事件驱动架构:观察者模式
  • 参数处理复杂:代理模式
  • React状态逻辑:自定义Hooks
  • 异步操作处理:异步代理模式

8.4 选择策略

场景 推荐方案 优势
简单逻辑复用 函数封装 简单直接
复杂对象创建 工厂模式 创建逻辑封装
全局状态管理 单例模式 保证唯一实例
参数处理复杂 代理模式 关注点分离
React状态逻辑 自定义Hooks 逻辑复用
异步操作 异步代理 Promise处理

8.5 性能考虑

  1. 代理开销:Proxy有一定性能开销,在性能敏感场景慎用
  2. 内存使用:高阶函数和闭包会增加内存占用
  3. 渲染优化:React中使用useCallback、useMemo避免不必要的重新渲染

8.6 代码组织建议

// 良好的代码结构
src/
├── utils/           # 纯函数工具
├── hooks/           # 自定义Hooks
├── proxies/         # 代理函数
├── factories/       # 工厂类
├── constants/       # 配置常量
└── validators/      # 验证逻辑

通过组合使用这些方案,可以显著提高JavaScript代码的复用性、可维护性和可测试性。根据具体场景选择合适的模式,避免过度设计,保持代码的简洁性和可读性。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐