面试题答案
一键面试1. TypeScript 装饰器在 Node.js 企业级后端应用中的应用场景
路由处理
在 Node.js 后端应用中,使用 Express 等框架时,装饰器可用于定义路由。例如:
import { Controller, Get, Post } from '@decorators/express';
@Controller('/api')
class MyController {
@Get('/users')
getUsers() {
// 处理获取用户列表逻辑
return 'User list';
}
@Post('/users')
createUser() {
// 处理创建用户逻辑
return 'User created';
}
}
这样可以将路由定义与业务逻辑紧密结合,使代码结构更清晰。
日志记录
装饰器可以方便地在方法调用前后添加日志记录。比如:
function log(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
const originalMethod = descriptor.value;
descriptor.value = function (...args: any[]) {
console.log(`Calling method ${propertyKey} with args:`, args);
const result = originalMethod.apply(this, args);
console.log(`Method ${propertyKey} returned:`, result);
return result;
};
return descriptor;
}
class MyService {
@log
doSomething() {
return 'Some result';
}
}
每次调用 doSomething
方法时,都会记录方法调用信息和返回结果。
权限控制
在企业级应用中,权限控制很重要。可以通过装饰器来检查用户是否有执行某个方法的权限。例如:
function checkPermission(role: string) {
return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
const originalMethod = descriptor.value;
descriptor.value = function (...args: any[]) {
const userRole = getCurrentUserRole(); // 假设此函数获取当前用户角色
if (userRole === role) {
return originalMethod.apply(this, args);
} else {
throw new Error('Permission denied');
}
};
return descriptor;
};
}
class AdminService {
@checkPermission('admin')
deleteUser() {
// 删除用户逻辑
return 'User deleted';
}
}
只有具有 admin
角色的用户才能调用 deleteUser
方法。
2. 自定义装饰器
类装饰器
类装饰器作用于类的定义。例如,为类添加元数据:
function addMetadata(meta: any) {
return function (target: Function) {
Reflect.defineMetadata('meta', meta, target);
};
}
@addMetadata({ key: 'value' })
class MyClass {}
const meta = Reflect.getMetadata('meta', MyClass);
console.log(meta); // { key: 'value' }
方法装饰器
方法装饰器作用于类的方法。前面日志记录和权限控制的例子就是方法装饰器。其结构一般为:
function myMethodDecorator(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
// 可以修改方法的行为
const originalMethod = descriptor.value;
descriptor.value = function (...args: any[]) {
// 前置逻辑
const result = originalMethod.apply(this, args);
// 后置逻辑
return result;
};
return descriptor;
}
属性装饰器
属性装饰器作用于类的属性。比如,验证属性值:
function validateNumber(target: any, propertyKey: string) {
let value: number;
const getter = function () {
return value;
};
const setter = function (newValue: number) {
if (typeof newValue!== 'number' || newValue < 0) {
throw new Error('Invalid number');
}
value = newValue;
};
Object.defineProperty(target, propertyKey, {
get: getter,
set: setter,
enumerable: true,
configurable: true
});
}
class MyData {
@validateNumber
myNumber: number;
}
const data = new MyData();
data.myNumber = 10; // 正常设置
// data.myNumber = 'not a number'; // 抛出错误
3. 使用装饰器时可能遇到的问题及解决方案
兼容性问题
问题:装饰器是 ES7 提案,在一些旧版本的 Node.js 环境中可能不支持。
解决方案:使用 Babel 进行转码,配置 @babel/plugin-proposal-decorators
插件,将装饰器语法转换为 ES5 兼容的代码。
装饰器执行顺序
问题:多个装饰器应用到同一个目标时,执行顺序可能不符合预期。 解决方案:了解装饰器执行顺序规则。类装饰器在类定义之前执行,方法装饰器、属性装饰器在类定义之后执行。多个装饰器从下往上(靠近目标的先执行)应用。
调试困难
问题:装饰器修改了原有方法或类的行为,调试时难以追踪。 解决方案:在装饰器内部添加详细的日志输出,记录装饰器的执行过程和参数。也可以使用调试工具,如 Node.js 自带的调试器或 IDE 的调试功能,逐步跟踪装饰器逻辑。
性能问题
问题:频繁使用装饰器,尤其是在方法装饰器中添加复杂逻辑,可能影响性能。 解决方案:尽量简化装饰器中的逻辑,避免在装饰器中执行耗时操作。如果需要复杂逻辑,可以考虑将其移到单独的服务中,装饰器只进行简单的调用。