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. 单一职责原则
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中一个强大的特性,它让我们能够以声明式的方式扩展和修改类的行为。我们学习了:
- 装饰器的基本概念和实现
- 高级装饰器模式和应用
- 实际应用场景
- 性能优化技巧
- 最佳实践和设计模式
💡 学习建议:在使用装饰器时,要注意保持装饰器的单一职责,避免过度使用。同时,要考虑装饰器对性能的影响,合理使用缓存和优化策略。
如果你觉得这篇文章有帮助,欢迎点赞收藏,也期待在评论区看到你的想法和建议!👇
终身学习,共同成长。
咱们下一期见
💻