当前位置: 首页 > article >正文

JavaScript系列(31)--装饰器详解

JavaScript装饰器详解 🎨

今天,让我们深入探讨JavaScript的装饰器(Decorators)。装饰器是一种用于修改类和类成员的强大语言特性,它让我们能够以声明式的方式增强类的功能。

装饰器基础概念 🌟

💡 小知识:装饰器是一种特殊的声明,可以被附加到类声明、方法、访问器、属性或参数上。装饰器使用 @expression 的形式,其中 expression 必须是一个函数,它会在运行时被调用。

基本装饰器实现 📊

// 1. 类装饰器
function classDecorator(target) {
    // 修改类的原型
    target.prototype.newMethod = function() {
        return 'Added by decorator';
    };
    
    // 添加静态属性
    target.staticProperty = 'Static Property';
    
    return target;
}

@classDecorator
class Example {
    constructor() {
        this.property = 'Original Property';
    }
}

// 2. 方法装饰器
function methodDecorator(target, propertyKey, descriptor) {
    // 保存原始方法
    const originalMethod = descriptor.value;
    
    // 修改方法
    descriptor.value = function(...args) {
        console.log(`Calling method ${propertyKey}`);
        const result = originalMethod.apply(this, args);
        console.log(`Method ${propertyKey} returned ${result}`);
        return result;
    };
    
    return descriptor;
}

class Calculator {
    @methodDecorator
    add(a, b) {
        return a + b;
    }
}

// 3. 属性装饰器
function propertyDecorator(target, propertyKey) {
    // 属性定义
    let value;
    
    // 定义getter和setter
    const getter = function() {
        console.log(`Getting ${propertyKey}`);
        return value;
    };
    
    const setter = function(newValue) {
        console.log(`Setting ${propertyKey} = ${newValue}`);
        value = newValue;
    };
    
    // 替换属性定义
    Object.defineProperty(target, propertyKey, {
        get: getter,
        set: setter,
        enumerable: true,
        configurable: true
    });
}

class User {
    @propertyDecorator
    name = 'Default Name';
}

高级装饰器模式 🚀

// 1. 参数验证装饰器
function validate(validator) {
    return function(target, propertyKey, descriptor) {
        const originalMethod = descriptor.value;
        
        descriptor.value = function(...args) {
            // 验证所有参数
            args.forEach((arg, index) => {
                if (!validator(arg)) {
                    throw new Error(
                        `Invalid argument ${index} for ${propertyKey}`
                    );
                }
            });
            
            return originalMethod.apply(this, args);
        };
        
        return descriptor;
    };
}

class UserService {
    @validate(value => typeof value === 'string' && value.length > 0)
    setUsername(name) {
        this.username = name;
    }
}

// 2. 缓存装饰器
function memoize(target, propertyKey, descriptor) {
    const originalMethod = descriptor.value;
    const cache = new Map();
    
    descriptor.value = function(...args) {
        const key = JSON.stringify(args);
        if (cache.has(key)) {
            return cache.get(key);
        }
        
        const result = originalMethod.apply(this, args);
        cache.set(key, result);
        return result;
    };
    
    return descriptor;
}

class MathOperations {
    @memoize
    fibonacci(n) {
        if (n <= 1) return n;
        return this.fibonacci(n - 1) + this.fibonacci(n - 2);
    }
}

// 3. 依赖注入装饰器
const Container = new Map();

function Injectable(key) {
    return function(target) {
        Container.set(key, target);
    };
}

function Inject(key) {
    return function(target, propertyKey) {
        Object.defineProperty(target, propertyKey, {
            get: () => Container.get(key),
            enumerable: true,
            configurable: true
        });
    };
}

@Injectable('userService')
class UserService {
    getUsers() {
        return ['User1', 'User2'];
    }
}

class UserController {
    @Inject('userService')
    userService;
    
    getUsers() {
        return this.userService.getUsers();
    }
}

装饰器应用场景 💼

// 1. 日志记录装饰器
function log(target, propertyKey, descriptor) {
    const originalMethod = descriptor.value;
    
    descriptor.value = async function(...args) {
        console.log(`[${new Date().toISOString()}] Calling ${propertyKey}`);
        try {
            const result = await originalMethod.apply(this, args);
            console.log(
                `[${new Date().toISOString()}] ${propertyKey} completed`
            );
            return result;
        } catch (error) {
            console.error(
                `[${new Date().toISOString()}] ${propertyKey} failed:`,
                error
            );
            throw error;
        }
    };
    
    return descriptor;
}

// 2. 权限控制装饰器
function authorize(roles = []) {
    return function(target, propertyKey, descriptor) {
        const originalMethod = descriptor.value;
        
        descriptor.value = function(...args) {
            const user = getCurrentUser(); // 假设这个函数存在
            if (!roles.includes(user.role)) {
                throw new Error('Unauthorized access');
            }
            return originalMethod.apply(this, args);
        };
        
        return descriptor;
    };
}

class AdminPanel {
    @authorize(['admin'])
    deleteUser(userId) {
        // 删除用户的逻辑
    }
}

// 3. 性能监控装饰器
function measure(target, propertyKey, descriptor) {
    const originalMethod = descriptor.value;
    
    descriptor.value = async function(...args) {
        const start = performance.now();
        try {
            const result = await originalMethod.apply(this, args);
            const end = performance.now();
            console.log(`${propertyKey} took ${end - start}ms`);
            return result;
        } catch (error) {
            const end = performance.now();
            console.error(
                `${propertyKey} failed after ${end - start}ms:`,
                error
            );
            throw error;
        }
    };
    
    return descriptor;
}

装饰器性能优化 ⚡

// 1. 装饰器工厂优化
class DecoratorFactory {
    static memoize(options = {}) {
        const { maxSize = 100, ttl = 3600000 } = options;
        
        return function(target, propertyKey, descriptor) {
            const cache = new Map();
            const originalMethod = descriptor.value;
            
            descriptor.value = function(...args) {
                const key = JSON.stringify(args);
                const now = Date.now();
                
                // 检查缓存是否过期
                if (cache.has(key)) {
                    const { value, timestamp } = cache.get(key);
                    if (now - timestamp < ttl) {
                        return value;
                    }
                    cache.delete(key);
                }
                
                // 控制缓存大小
                if (cache.size >= maxSize) {
                    const oldestKey = cache.keys().next().value;
                    cache.delete(oldestKey);
                }
                
                const result = originalMethod.apply(this, args);
                cache.set(key, { value: result, timestamp: now });
                return result;
            };
            
            return descriptor;
        };
    }
}

// 2. 装饰器组合优化
function composeDecorators(...decorators) {
    return function(target, propertyKey, descriptor) {
        return decorators.reduceRight((desc, decorator) => {
            return decorator(target, propertyKey, desc);
        }, descriptor);
    };
}

// 3. 异步装饰器优化
function asyncDecorator(target, propertyKey, descriptor) {
    const originalMethod = descriptor.value;
    const promiseCache = new WeakMap();
    
    descriptor.value = async function(...args) {
        if (!promiseCache.has(this)) {
            promiseCache.set(this, new Map());
        }
        
        const cache = promiseCache.get(this);
        const key = JSON.stringify(args);
        
        if (cache.has(key)) {
            return cache.get(key);
        }
        
        const promise = originalMethod.apply(this, args);
        cache.set(key, promise);
        
        try {
            const result = await promise;
            return result;
        } finally {
            cache.delete(key);
        }
    };
    
    return descriptor;
}

最佳实践建议 💡

  1. 装饰器设计模式
// 1. 单一职责原则
function singleResponsibility(target, propertyKey, descriptor) {
    // 每个装饰器只做一件事
    const originalMethod = descriptor.value;
    
    descriptor.value = function(...args) {
        // 只负责日志记录
        console.log(`Calling ${propertyKey}`);
        return originalMethod.apply(this, args);
    };
    
    return descriptor;
}

// 2. 可组合装饰器
function composable(middleware) {
    return function(target, propertyKey, descriptor) {
        const originalMethod = descriptor.value;
        
        descriptor.value = function(...args) {
            return middleware(originalMethod.bind(this))(...args);
        };
        
        return descriptor;
    };
}

// 3. 可配置装饰器
function configurable(options = {}) {
    return function(target, propertyKey, descriptor) {
        return {
            ...descriptor,
            configurable: options.configurable ?? true,
            enumerable: options.enumerable ?? true,
            writable: options.writable ?? true
        };
    };
}

结语 📝

装饰器是JavaScript中一个强大的特性,它让我们能够以声明式的方式扩展和修改类的行为。我们学习了:

  1. 装饰器的基本概念和实现
  2. 高级装饰器模式和应用
  3. 实际应用场景
  4. 性能优化技巧
  5. 最佳实践和设计模式

💡 学习建议:在使用装饰器时,要注意保持装饰器的单一职责,避免过度使用。同时,要考虑装饰器对性能的影响,合理使用缓存和优化策略。


如果你觉得这篇文章有帮助,欢迎点赞收藏,也期待在评论区看到你的想法和建议!👇

终身学习,共同成长。

咱们下一期见

💻


http://www.kler.cn/a/507436.html

相关文章:

  • Android 12.0 息屏休眠后立即启动屏保功能实现
  • 基于Java的百度AOI数据解析与转换的实现方法
  • 【Qt】03-页面切换
  • 玩转随机数:用 JavaScript 掌控不可预测的魔力!
  • 如何使用PHP构建IoC容器,实现依赖注入!
  • 【学习笔记】理解深度学习的基础:机器学习
  • uc/os-II 原理及应用(八) 系统裁减以及移植到51单片机-下
  • Redis登录优化
  • YUV转RGB
  • Python编程与机器学习:解锁气象、海洋、水文领域的新实践
  • 从 0 开始实现一个 SpringBoot + Vue 项目
  • windows远程桌面连接限定ip
  • HTTP 性能优化策略
  • 【设计模式】 单例模式(单例模式哪几种实现,如何保证线程安全,反射破坏单例模式)
  • 关于ubuntu命令行连接github失败解决办法
  • 小哆啦的跳跃挑战:能否突破迷宫的极限?
  • 【北京迅为】iTOP-4412全能版使用手册-第七部分 Android入门教程
  • 【QT】: 初识 QWidget 控件 | QWidget 核心属性(API) | qrc 文件
  • el-dialog弹窗的@open方法中,第一次引用ref发现undefined问题,第二次后面又正常了
  • 微服务容器化部署好处多吗?
  • 记录一个v-if与自定义指令的BUG
  • 使用 ChatGPT 生成和改进你的论文
  • 【Javascript Day10】Math对象、Math随机数、时间对象
  • LabVIEW实车四轮轮速信号再现系统
  • tomcat项目运行后报500
  • Java 高级工程师面试高频题:JVM+Redis+ 并发 + 算法 + 框架