JavaScript装饰器是一个强大的语言特性,它让我们能够以声明式的方式修改类和类成员的行为。本文将深入探讨装饰器的原理、使用方法和最佳实践。
小知识:装饰器是一种特殊类型的声明,它能够被附加到类声明、方法、访问器、属性或参数上。装饰器使用
@expression
形式,其中 expression 必须计算为一个函数。
// 基础装饰器语法
function readonly(target, key, descriptor) {
descriptor.writable = false;
return descriptor;
}
class Example {
@readonly
pi() { return 3.14; }
}
function logger(logPrefix) {
return function(target) {
// 保存原始方法
const methods = Object.getOwnPropertyNames(target.prototype);
methods.forEach(method => {
if (method !== 'constructor') {
const descriptor = Object.getOwnPropertyDescriptor(
target.prototype,
method
);
const originalMethod = descriptor.value;
descriptor.value = function(...args) {
console.log(`${logPrefix} Calling ${method}`);
const result = originalMethod.apply(this, args);
console.log(`${logPrefix} Finished ${method}`);
return result;
};
Object.defineProperty(target.prototype, method, descriptor);
}
});
};
}
@logger('[UserService]')
class UserService {
login() { /* ... */ }
logout() { /* ... */ }
}
function measure(target, key, descriptor) {
const originalMethod = descriptor.value;
descriptor.value = function(...args) {
const start = performance.now();
const result = originalMethod.apply(this, args);
const end = performance.now();
console.log(`${key} took ${end - start}ms`);
return result;
};
return descriptor;
}
class API {
@measure
async fetchData() {
// 模拟API调用
await new Promise(resolve => setTimeout(resolve, 1000));
return { data: 'success' };
}
}
function validate(validationFn) {
return function(target, key) {
let value = target[key];
const getter = () => value;
const setter = (newValue) => {
if (!validationFn(newValue)) {
throw new Error('Invalid value');
}
value = newValue;
};
Object.defineProperty(target, key, {
get: getter,
set: setter,
enumerable: true,
configurable: true
});
};
}
class User {
@validate(value => value.length >= 3)
name = '';
}
function authorize(role) {
return function(target, key, descriptor) {
const originalMethod = descriptor.value;
descriptor.value = function(...args) {
if (!this.currentUser || this.currentUser.role !== role) {
throw new Error('Unauthorized access');
}
return originalMethod.apply(this, args);
};
return descriptor;
};
}
class AdminPanel {
@authorize('admin')
deleteUser(userId) {
// 删除用户逻辑
}
}
function memoize(target, key, 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 MathUtils {
@memoize
fibonacci(n) {
if (n <= 1) return n;
return this.fibonacci(n - 1) + this.fibonacci(n - 2);
}
}
function debounce(delay) {
return function(target, key, descriptor) {
const originalMethod = descriptor.value;
let timeoutId;
descriptor.value = function(...args) {
clearTimeout(timeoutId);
timeoutId = setTimeout(() => {
originalMethod.apply(this, args);
}, delay);
};
return descriptor;
};
}
class SearchComponent {
@debounce(300)
search(query) {
// 执行搜索逻辑
}
}
保持简单性
错误处理
function errorBoundary(target, key, descriptor) {
const originalMethod = descriptor.value;
descriptor.value = async function(...args) {
try {
return await originalMethod.apply(this, args);
} catch (error) {
console.error(`Error in ${key}:`, error);
// 可以添加错误报告逻辑
throw error;
}
};
return descriptor;
}
function validateParams(...validators) {
return function(target, key, descriptor) {
const originalMethod = descriptor.value;
descriptor.value = function(...args) {
validators.forEach((validator, index) => {
if (!validator(args[index])) {
throw new Error(`Invalid parameter at position ${index}`);
}
});
return originalMethod.apply(this, args);
};
return descriptor;
};
}
避免过度使用
缓存装饰器结果
function cached(target, key, descriptor) {
const originalMethod = descriptor.value;
const cache = new WeakMap();
descriptor.value = function(...args) {
if (!cache.has(this)) {
cache.set(this, new Map());
}
const methodCache = cache.get(this);
const key = JSON.stringify(args);
if (methodCache.has(key)) {
return methodCache.get(key);
}
const result = originalMethod.apply(this, args);
methodCache.set(key, result);
return result;
};
return descriptor;
}
装饰器是JavaScript中一个强大的特性,它能够:
学习建议:
- 从简单的装饰器开始学习
- 理解装饰器的工作原理
- 在实际项目中谨慎使用
- 注意性能影响
- 保持代码的可维护性
如果你觉得这篇文章有帮助,欢迎点赞收藏,也期待在评论区看到你的想法和建议!
终身学习,共同成长。
咱们下一期见