面试题答案
一键面试设计原则
- 性能优化:
- 减少重复计算:装饰器执行的操作应该尽可能高效,避免在每次调用被装饰函数时进行重复的计算。例如,对于权限控制,如果权限判断结果在短时间内不会改变,可以使用缓存机制。
- 惰性求值:对于一些非必要的装饰器逻辑,采用惰性求值的方式,只有在真正需要时才执行。比如日志记录,只有在开启详细日志模式时才记录详细信息。
- 可维护性:
- 单一职责原则:每个装饰器应该只负责一项功能,例如权限控制装饰器只处理权限相关逻辑,日志记录装饰器专注于日志记录。这样当需求变化时,只需要修改对应的装饰器代码,不会影响其他功能。
- 清晰的代码结构:装饰器代码应该有良好的注释和清晰的逻辑结构,便于其他开发人员理解和修改。
- 扩展性:
- 模块化设计:将不同功能的装饰器封装成独立的模块,方便在不同项目或模块中复用。同时,新的装饰器功能可以很容易地添加进来,而不影响现有的装饰器系统。
- 配置化管理:通过配置文件或配置对象来管理装饰器的应用,这样可以灵活地根据不同的环境或需求启用或禁用某些装饰器。
避免装饰器相互干扰
- 作用域隔离:每个装饰器应该在自己独立的作用域内执行,避免在全局作用域中共享变量。例如,在JavaScript中可以使用闭包来创建独立作用域。
- 命名规范:为装饰器及其内部使用的变量采用统一且唯一的命名规范,防止命名冲突。
动态加载和卸载装饰器
- 动态加载:
- 基于配置文件:在项目启动时,读取配置文件,根据配置决定需要加载哪些装饰器。例如在Node.js项目中,可以读取JSON或YAML格式的配置文件。
- 条件判断:在代码中根据运行时条件判断是否加载某个装饰器。比如根据用户角色判断是否加载权限控制装饰器。
- 动态卸载:
- 提供卸载函数:为每个装饰器提供一个卸载函数,在需要卸载时调用该函数,恢复被装饰函数的原始状态。
- 使用代理对象:通过代理对象来管理被装饰函数,在卸载装饰器时,重新创建一个没有应用装饰器的代理对象。
代码架构示例(以JavaScript和TypeScript为例)
- 权限控制装饰器:
// 权限控制装饰器
function checkPermission(role: string) {
return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
const originalMethod = descriptor.value;
descriptor.value = function (...args: any[]) {
// 模拟权限检查逻辑
const currentRole = getCurrentRole();
if (currentRole === role) {
return originalMethod.apply(this, args);
} else {
throw new Error('没有权限');
}
};
return descriptor;
};
}
function getCurrentRole() {
// 实际项目中从认证系统获取当前用户角色
return 'admin';
}
class MyClass {
@checkPermission('admin')
myMethod() {
console.log('执行方法');
}
}
- 日志记录装饰器:
// 日志记录装饰器
function log(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
const originalMethod = descriptor.value;
descriptor.value = function (...args: any[]) {
console.log(`调用 ${propertyKey} 方法,参数:`, args);
const result = originalMethod.apply(this, args);
console.log(`${propertyKey} 方法执行完毕,结果:`, result);
return result;
};
return descriptor;
}
class AnotherClass {
@log
anotherMethod() {
return '返回值';
}
}
- 动态加载和卸载示例:
// 动态加载装饰器示例
function loadDecorator(decorator: Function, target: any, propertyKey: string, descriptor: PropertyDescriptor) {
return decorator(target, propertyKey, descriptor);
}
// 动态卸载装饰器示例
function unloadDecorator(target: any, propertyKey: string, originalDescriptor: PropertyDescriptor) {
Object.defineProperty(target, propertyKey, originalDescriptor);
}
class DynamicClass {
myDynamicMethod() {
console.log('动态方法');
}
}
// 动态加载日志记录装饰器
const dynamicClass = new DynamicClass();
const originalDescriptor = Object.getOwnPropertyDescriptor(DynamicClass.prototype,'myDynamicMethod');
const newDescriptor = loadDecorator(log, DynamicClass.prototype,'myDynamicMethod', originalDescriptor!);
Object.defineProperty(DynamicClass.prototype,'myDynamicMethod', newDescriptor);
// 动态卸载日志记录装饰器
unloadDecorator(DynamicClass.prototype,'myDynamicMethod', originalDescriptor!);
通过上述设计和代码示例,可以构建一个高效、可维护且可扩展的装饰器系统,满足大型前端项目中权限控制、日志记录等功能的需求。