# Reflect
Reflect 是 ES6 引入的一个内置对象,提供了一组用于操作对象的方法。
const obj = { name: 'Alice', age: 25 }
// 获取属性
console.log(Reflect.get(obj, 'name')) // 输出: Alice
// 设置属性
Reflect.set(obj, 'age', 30)
console.log(obj.age) // 输出: 30
// 检查属性
console.log(Reflect.has(obj, 'name')) // 输出: true
// 删除属性
Reflect.deleteProperty(obj, 'age')
console.log(obj.age) // 输出: undefined
# reflect-metadata
reflect-metadata 是一个库,用于在类、方法或属性上存储额外的信息。
import 'reflect-metadata'
function MyDecorator(metadataValue) {
return function (target, propertyKey) {
Reflect.defineMetadata('myMetadataKey', metadataValue, target, propertyKey)
}
}
class MyClass {
@MyDecorator('some value')
myMethod() {}
}
const metadataValue = Reflect.getMetadata('myMetadataKey', MyClass.prototype, 'myMethod')
console.log(metadataValue) // 输出: some value
# 装饰器
JavaScript 中,由于装饰器目前仍然是 ECMAScript 的提案(尚未正式成为标准),因此需要通过 Babel 等工具来支持装饰器语法。
TypeScript 原生支持装饰器语法,并且是 NestJS 的推荐开发语言。
# 1、类装饰器
// 服务注册表
const serviceRegistry: Map<string, any> = new Map()
// 类装饰器:自动注册服务
function Service(name: string) {
return function (target: Function) {
console.log(`Registering service: ${name}`)
serviceRegistry.set(name, target)
}
}
@Service('UserService')
class UserService {
getUsers(): string[] {
return ['Alice', 'Bob']
}
}
// 从注册表中获取服务
const UserServiceClass = serviceRegistry.get('UserService')
const userService = new UserServiceClass()
console.log(userService.getUsers()) // 输出: ['Alice', 'Bob']
# 2、方法装饰器
方法装饰器是 JavaScript/TypeScript 中实现 AOP 的一种方式。
略:Proxy 对象、高阶函数等也可以实现 AOP
- 日志记录功能
// 定义一个日志装饰器(切面)
function log(target: any, key: string, descriptor: PropertyDescriptor) {
const originalMethod = descriptor.value
// 修改方法的行为(环绕通知)
descriptor.value = function (...args: any[]) {
console.log(`[LOG] Calling method: ${key} with arguments: ${JSON.stringify(args)}`)
const result = originalMethod.apply(this, args)
console.log(`[LOG] Method ${key} returned: ${result}`)
return result
}
return descriptor
}
class MyClass {
@log
add(a: number, b: number): number {
return a + b
}
}
const instance = new MyClass()
console.log(instance.add(2, 3)) // 调用方法并记录日志
- 用户权限校验
function checkPermission(role: string) {
return function (target: any, key: string, descriptor: PropertyDescriptor) {
const originalMethod = descriptor.value
descriptor.value = function (...args: any[]) {
if (role === 'admin') {
return originalMethod.apply(this, args)
} else {
throw new Error('Permission denied')
}
}
}
}
class MyClass {
@checkPermission('admin')
deleteResource() {
console.log('Resource deleted')
}
}
- 执行时间记录
// 方法装饰器:记录方法执行时间
function logExecutionTime(target: any, key: string, descriptor: PropertyDescriptor) {
const originalMethod = descriptor.value
descriptor.value = function (...args: any[]) {
const start = performance.now()
const result = originalMethod.apply(this, args)
const end = performance.now()
console.log(`Method ${key} executed in ${end - start}ms`)
return result
}
return descriptor
}
class DataService {
@logExecutionTime
fetchData(): Promise<string[]> {
return new Promise((resolve) => {
setTimeout(() => resolve(['Data1', 'Data2']), 1000)
})
}
}
const dataService = new DataService()
dataService.fetchData().then((data) => console.log(data))
# 3、访问器装饰器
略:用于修饰类的 getter 或 setter,常用于数据验证
# 4、属性装饰器
可以对类的属性进行各类操作,不限于默认值、校验、监听、加密、懒加载、只读等
function validateRange(min: number, max: number) {
return function (target: any, key: string) {
let value = target[key]
const getter = function () {
return value
}
const setter = function (newValue: number) {
if (newValue < min || newValue > max) {
throw new Error(`Value of ${key} must be between ${min} and ${max}`)
}
value = newValue
}
Object.defineProperty(target, key, {
get: getter,
set: setter,
enumerable: true,
configurable: true
})
}
}
class Product {
@validateRange(0, 100)
discount: number = 0
}
const product = new Product()
product.discount = 50 // 正常设置
console.log(product.discount) // 输出: 50
product.discount = 150 // 抛出错误: Value of discount must be between 0 and 100
# 5、参数装饰器
参数装饰器用于修饰类方法的参数,常用于添加元数据或验证参数。
// 参数装饰器:验证参数是否为正数
function validatePositive(target: any, key: string, parameterIndex: number) {
const originalMethod = target[key]
target[key] = function (...args: any[]) {
const value = args[parameterIndex]
if (typeof value === 'number' && value <= 0) {
throw new Error(`Parameter at index ${parameterIndex} must be positive`)
}
return originalMethod.apply(this, args)
}
}
class Calculator {
add(@validatePositive a: number, @validatePositive b: number): number {
return a + b
}
}
const calculator = new Calculator()
console.log(calculator.add(5, 10)) // 输出: 15
console.log(calculator.add(-1, 10)) // 抛出错误: Parameter at index 0 must be positive
# 装饰器执行顺序
参数装饰器 > 方法装饰器/访问器装饰器 > 属性装饰器 > 类装饰器。
// 类装饰器
function ClassDecorator() {
console.log('Class Decorator')
return function (target: any) {
console.log('Class Decorator Logic')
}
}
// 方法装饰器
function MethodDecorator() {
console.log('Method Decorator')
return function (target: any, key: string, descriptor: PropertyDescriptor) {
console.log('Method Decorator Logic')
}
}
// 访问器装饰器
function AccessorDecorator() {
console.log('Accessor Decorator')
return function (target: any, key: string, descriptor: PropertyDescriptor) {
console.log('Accessor Decorator Logic')
}
}
// 属性装饰器
function PropertyDecorator() {
console.log('Property Decorator')
return function (target: any, key: string) {
console.log('Property Decorator Logic')
}
}
// 参数装饰器
function ParameterDecorator() {
console.log('Parameter Decorator')
return function (target: any, key: string, parameterIndex: number) {
console.log('Parameter Decorator Logic')
}
}
@ClassDecorator()
class MyClass {
@PropertyDecorator()
myProperty: string = 'Hello'
@AccessorDecorator()
get myAccessor(): string {
return this.myProperty
}
@MethodDecorator()
myMethod(@ParameterDecorator() param: string) {
console.log(param)
}
}
// 实例化类
const instance = new MyClass()
instance.myMethod('World')
nestjs基础 →