# 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')
更新于 : 4/13/2025, 5:16:17 AM