Skip to content

JS装饰器(Decorator)完全指南 🎨 ​

什么是装饰器? ​

装饰器(Decorator)是一种特殊类型的声明,它能够被附加到类声明、方法、属性或参数上,可以用来修改类的行为。通俗来说,装饰器就是一个函数,用来修改类的行为。

🔔 注意:目前装饰器已进入 Stage 3 提案阶段,即将成为 ECMAScript 的标准特性。

前置准备工作 ⚙️ ​

1. 开发环境配置 ​

  • VSCode 设置中启用装饰器语法支持
  • 确保 TypeScript 配置中 experimentalDecorators 选项为 true

2. 必要依赖安装 📦 ​

bash
npm install --save-dev @babel/plugin-proposal-decorators @babel/plugin-proposal-class-properties

3. Babel 配置 🛠️ ​

json
{
  "babel": {
    "presets": ["react-app"],
    "plugins": [
      ["@babel/plugin-proposal-decorators", { "version": "2023-05" }],
      ["@babel/plugin-proposal-class-properties"]
    ]
  }
}

装饰器的使用方式 💡 ​

1. 类装饰器 ​

类装饰器用于整个类的声明之前,可以监视、修改或替换类的定义。

javascript
// 基础类装饰器
const logger = (target) => {
  // target 是类本身
  target.logger = true;
  target.prototype.log = function(...args) {
    console.log(...args);
  }
};

@logger
class Example {
  constructor() {
    console.log('Creating new instance');
  }
}

// 装饰器工厂(带参数的装饰器)
const withPrefix = (prefix) => {
  return (target) => {
    target.prototype.getNameWithPrefix = function() {
      return `${prefix}_${this.name}`;
    }
  }
};

@withPrefix('app')
class User {
  name = 'john';
}

2. 方法装饰器 🔧 ​

方法装饰器可以用来监视、修改或者替换方法定义。

javascript
// 性能监控装饰器
const measurePerformance = (target, propertyKey, descriptor) => {
  const originalMethod = descriptor.value;
  
  descriptor.value = function(...args) {
    const start = performance.now();
    const result = originalMethod.apply(this, args);
    const end = performance.now();
    console.log(`${propertyKey} 执行时间: ${end - start}ms`);
    return result;
  };
  
  return descriptor;
};

class API {
  @measurePerformance
  async fetchData() {
    // 模拟API调用
    await new Promise(resolve => setTimeout(resolve, 1000));
    return { data: 'success' };
  }
}

3. 属性装饰器 📝 ​

javascript
// 只读属性装饰器
const readonly = (target, propertyKey) => {
  Object.defineProperty(target, propertyKey, {
    writable: false
  });
};

class Config {
  @readonly
  static VERSION = '1.0.0';
}

实践建议 ✨ ​

  1. 性能考虑:装饰器会在类定义时执行,而不是实例化时,要注意性能开销。

  2. 调试技巧:使用装饰器时,建议添加适当的日志,便于调试。

  3. 最佳实践:

    • 保持装饰器功能单一
    • 避免在装饰器中进行过重的计算
    • 合理使用装饰器工厂来传递参数

常见应用场景 🎯 ​

  1. 权限控制
javascript
const requireAuth = (target, propertyKey, descriptor) => {
  const originalMethod = descriptor.value;
  
  descriptor.value = function(...args) {
    if (!this.isAuthenticated) {
      throw new Error('未授权访问');
    }
    return originalMethod.apply(this, args);
  };
};
  1. 数据验证
javascript
const validateParams = (schema) => {
  return (target, propertyKey, descriptor) => {
    const originalMethod = descriptor.value;
    
    descriptor.value = function(...args) {
      const valid = schema.validate(args[0]);
      if (!valid) {
        throw new Error('参数验证失败');
      }
      return originalMethod.apply(this, args);
    };
  };
};

注意事项 ⚠️ ​

  1. 装饰器执行顺序:从下到上,从右到左
  2. 不同类型装饰器的参数可能不同
  3. 某些装饰器可能会影响类的原型链
  4. 需要注意浏览器兼容性问题

💡 提示:建议在正式使用装饰器之前,先在测试环境中充分验证其行为。