面试题答案
一键面试性能问题场景分析
- 频繁调用场景:如果属性装饰器内部执行复杂逻辑,且该属性被频繁访问或修改,每次操作都触发装饰器逻辑,会导致性能开销增大。例如在一个实时数据更新的图表组件中,属性频繁变化且装饰器中有复杂计算。
- 大量实例场景:当创建大量带有属性装饰器的实例时,如果装饰器逻辑占用较多资源,会导致内存消耗增大和实例创建性能下降。比如在一个包含成百上千个列表项的列表组件,每个列表项实例都使用了属性装饰器。
性能优化方法
- 缓存结果:在装饰器内部对频繁计算的结果进行缓存。例如,如果装饰器逻辑是对某个属性值进行复杂计算,可以将计算结果缓存起来,下次访问直接返回缓存值。
function cacheValue(target: any, propertyKey: string) {
let cache: any;
const originalGetter = Object.getOwnPropertyDescriptor(target, propertyKey)?.get;
Object.defineProperty(target, propertyKey, {
get() {
if (cache === undefined) {
cache = originalGetter?.call(this);
}
return cache;
}
});
}
- 减少不必要操作:优化装饰器内部逻辑,避免不必要的计算和操作。比如在属性值未发生变化时,不重复执行相同的逻辑。
- 延迟初始化:对于一些不急需的操作,可以延迟到首次访问属性时再执行。
代码可维护性和复用性示例
- 权限控制场景:在一个后台管理系统中,不同用户角色对页面某些属性有不同的访问权限。可以使用属性装饰器来控制属性的访问。
function canAccess(role: string) {
return function (target: any, propertyKey: string) {
let value: any;
const originalGetter = Object.getOwnPropertyDescriptor(target, propertyKey)?.get;
Object.defineProperty(target, propertyKey, {
get() {
if (currentUser.role === role) {
return originalGetter?.call(this);
}
return null; // 或者抛出权限不足错误
}
});
};
}
class AdminPanel {
@canAccess('admin')
sensitiveData: string = 'confidential information';
}
这样通过属性装饰器,将权限控制逻辑封装起来,当需要对其他属性进行权限控制时,只需复用 canAccess
装饰器,提高了代码的复用性。同时,如果权限控制逻辑发生变化,只需在装饰器内部修改,增强了代码的可维护性。
2. 日志记录场景:在一个电商订单处理模块中,对订单属性的修改进行日志记录。
function logPropertyChange(target: any, propertyKey: string) {
let value: any;
const originalSetter = Object.getOwnPropertyDescriptor(target, propertyKey)?.set;
Object.defineProperty(target, propertyKey, {
set(newValue) {
console.log(`${propertyKey} changed from ${value} to ${newValue}`);
value = newValue;
originalSetter?.call(this, newValue);
}
});
}
class Order {
@logPropertyChange
orderStatus: string = 'pending';
}
通过属性装饰器实现日志记录逻辑,当有其他需要记录属性变化的场景时,直接复用该装饰器,提高了代码复用性。若日志记录方式改变,只需要修改装饰器代码,增强了代码可维护性。