09. JS 装饰器 
1. 装饰器是什么? 
装饰器(Decorator)是一种特殊类型的声明,用于为类、方法、属性或访问器添加元编程功能。其本质是一个函数,通过@符号作为标识符,可以:
- 修改类定义
- 扩展方法行为
- 添加元数据
- 实现AOP(面向切面编程)
示例:
javascript
@log // 类装饰器
class Calculator {
  @memoize // 方法装饰器
  sum(a, b) {
    return a + b
  }
}2. JavaScript 装饰器的起源 
发展历程:
- 2014 年首次出现在 TypeScript 1.5
- 2018 年进入 TC39 提案 Stage 2
- 2022 年更新为 Stage 3(当前状态)
- 需要 Babel/TypeScript 转译支持
标准实现差异:
| 环境 | 语法支持 | 配置方式 | 
|---|---|---|
| Babel | 需要插件 | @babel/plugin-proposal-decorators | 
| TypeScript | 实验特性 | tsconfig.json中开启experimentalDecorators | 
3. 类的装饰 
基本结构:
javascript
function classDecorator(target) {
  return class extends target {
    // 扩展类功能
  }
}
@classDecorator
class MyClass {}参数说明:
- 参数 1:被装饰的类构造函数
- 返回值:新的类构造函数
示例:添加版本信息
javascript
function withVersion(version) {
  return function(target) {
    target.prototype.version = version
    return target
  }
}
@withVersion('1.0.0')
class App {}4. 方法或成员的装饰 
方法装饰器签名:
javascript
function methodDecorator(target, name, descriptor) {
  const originalMethod = descriptor.value
  descriptor.value = function(...args) {
    // 方法逻辑扩展
    return originalMethod.apply(this, args)
  }
  return descriptor
}参数说明:
| 参数 | 说明 | 
|---|---|
| target | 类的原型对象 | 
| name | 被装饰成员的名称 | 
| descriptor | 属性描述符( Object.defineProperty使用) | 
属性描述符结构:
javascript
{
  value: 当前值,
  enumerable: 是否可枚举,
  configurable: 是否可配置,
  writable: 是否可写
}示例:防抖装饰器
javascript
function debounce(delay = 300) {
  return function(target, name, descriptor) {
    let timeout
    const original = descriptor.value
  
    descriptor.value = function(...args) {
      clearTimeout(timeout)
      timeout = setTimeout(() => {
        original.apply(this, args)
      }, delay)
    }
  
    return descriptor
  }
}
class SearchBox {
  @debounce(500)
  search(query) {
    // 搜索逻辑
  }
}5. 为什么装饰器不用于函数 
规范限制原因:
- 函数提升(Hoisting)导致装饰顺序不可控
- 箭头函数的 this绑定问题
- 避免与函数表达式混淆
错误示例:
javascript
// 以下写法在规范中不被支持
@log
function myFunction() {}替代方案:
javascript
// 使用高阶函数包装
const decoratedFn = log(function() {})6. 实践:实现日志记录 
完整日志装饰器实现:
javascript
function log(target, name, descriptor) {
  const original = descriptor.value
  descriptor.value = function(...args) {
    console.log(`[调用] ${name} 参数: ${JSON.stringify(args)}`)
    const start = Date.now()
    const result = original.apply(this, args)
    console.log(`[完成] ${name} 耗时: ${Date.now() - start}ms`)
    return result
  }
  return descriptor
}
class API {
  @log
  async fetchData(url) {
    const response = await fetch(url)
    return response.json()
  }
}
// 使用示例
const api = new API()
api.fetchData('https://api.example.com/data')输出结果:
text
[调用] fetchData 参数: ["https://api.example.com/data"]
[完成] fetchData 耗时: 352ms配置指南:
- 安装 Babel 支持bashnpm install --save-dev @babel/plugin-proposal-decorators
- 配置 .babelrcjson{ "plugins": [ ["@babel/plugin-proposal-decorators", { "version": "2022-03" }] ] }