面试题答案
一键面试1. 类装饰器的工厂函数
类装饰器工厂函数是一个返回类装饰器的函数,这种方式增加了装饰器的灵活性。
示例:日志记录装饰器工厂函数
function Logger(logLevel: 'debug' | 'info' | 'error') {
return function (target: Function) {
const originalMethod = target.prototype.render;
target.prototype.render = function () {
if (logLevel === 'debug') {
console.debug('Rendering component...');
} else if (logLevel === 'info') {
console.info('Rendering component...');
} else {
console.error('Error while rendering component');
}
return originalMethod.apply(this, arguments);
};
};
}
优势
- 可配置性:通过传入不同参数(如上述的
logLevel
),可以灵活定制装饰器行为。 - 复用性:同一工厂函数可根据不同配置创建多个不同行为的装饰器。
2. 多装饰器组合
在一个类上应用多个装饰器,能实现多方面功能增强。
示例:组合日志记录、性能监控和权限控制装饰器
function PerformanceMonitor(target: Function) {
const originalMethod = target.prototype.render;
target.prototype.render = function () {
const start = Date.now();
const result = originalMethod.apply(this, arguments);
const end = Date.now();
console.log(`Rendering took ${end - start} ms`);
return result;
};
}
function AuthCheck(target: Function) {
const originalMethod = target.prototype.render;
target.prototype.render = function () {
const hasPermission = true; // 这里替换为实际权限检查逻辑
if (hasPermission) {
return originalMethod.apply(this, arguments);
} else {
throw new Error('Permission denied');
}
};
}
@Logger('info')
@PerformanceMonitor
@AuthCheck
class MyComponent {
render() {
// 组件渲染逻辑
return 'Component rendered';
}
}
执行顺序
- 装饰器应用顺序从下往上,而实际执行顺序是从上往下。即先应用
Logger
,再PerformanceMonitor
,最后AuthCheck
;但执行时先执行Logger
的逻辑,接着PerformanceMonitor
,最后AuthCheck
。
3. 避免装饰器之间的冲突
- 命名规范:确保不同装饰器使用的属性或方法名称不会冲突。例如,在上述装饰器中,都围绕
render
方法进行增强,不会产生命名冲突。 - 依赖明确:清楚每个装饰器的依赖关系,避免出现循环依赖。例如,如果
AuthCheck
依赖于PerformanceMonitor
的某些计算结果,这种依赖关系应清晰定义。
4. 依赖管理
- 外部依赖:如果装饰器依赖外部库(如日志库、权限管理库),应使用模块系统(如ES6模块)来管理这些依赖。确保在项目构建时,依赖能够正确引入和处理。
- 内部依赖:对于装饰器之间的内部依赖,通过设计清晰的接口和调用顺序来管理。例如,
PerformanceMonitor
装饰器可能依赖于Logger
装饰器输出的某些信息,这种依赖关系应在文档或代码注释中明确说明。
5. 提高可维护性
- 文档化:为每个装饰器编写详细的文档,说明其功能、参数含义、依赖关系以及使用方法。
- 模块化:将每个装饰器及其相关逻辑封装成独立模块,便于管理和维护。例如,将日志记录装饰器相关代码放在
logger.decorator.ts
文件中。 - 测试:为每个装饰器编写单元测试,确保其功能正确,并且在组合使用时不会出现意外情况。