返回

JavaScript装饰器的魔法:5个技巧让你惊艳全场

前端

JavaScript 装饰器的魔力:5个技巧让你的代码惊艳全场

解锁 JavaScript 装饰器的强大功能

JavaScript 装饰器是一种令人惊叹的技术,它允许你为类和函数注入额外的行为,而无需修改原始代码。这就像给你的代码穿上隐形斗篷,让他们拥有更强大的能力,而无需触及任何内部结构。

1. 神奇的函数参数装饰

想象一下,你可以检查函数的参数,确保它们是正确的类型,或者在每次调用函数时记录它们。装饰器让你轻而易举地做到这一点!只需将一个装饰器函数附加到函数参数上,它就会在你需要时执行代码。

function checkParameterType(type) {
  return function(target, propertyKey, parameterIndex) {
    console.log(`Checking parameter ${parameterIndex} of function ${propertyKey}`);
    if (typeof target[parameterIndex] !== type) {
      throw new Error(`Parameter ${parameterIndex} of function ${propertyKey} must be of type ${type}`);
    }
  };
}

function myFunction(name) {
  console.log(`Hello, ${name}!`);
}

myFunction = checkParameterType("string")(myFunction);

myFunction("John"); // 输出:"Hello, John!"
myFunction(123); // 输出错误

2. 窥探类属性

装饰器还可以监视类属性,让你在每次访问或修改它们时获得通知。这就像一个秘密特工,在你不知不觉中潜伏在后台,记录着属性的一举一动。

function logPropertyAccess(target, propertyKey) {
  console.log(`Accessing property ${propertyKey} of class ${target.name}`);
}

class MyClass {
  @logPropertyAccess
  name = "JavaScript";
}

const myClassInstance = new MyClass();
myClassInstance.name; // 输出:"Accessing property name of class MyClass"

3. 揭示函数返回值

好奇函数的返回值吗?装饰器可以帮你!你可以使用它们来验证返回值类型,或者记录每次函数被调用的结果。

function logFunctionReturnValue(target, propertyKey, descriptor) {
  const originalMethod = descriptor.value;

  descriptor.value = function(...args) {
    const result = originalMethod.apply(this, args);
    console.log(`Function ${propertyKey} returned ${result}`);
    return result;
  };

  return descriptor;
}

class MyClass {
  @logFunctionReturnValue
  calculateSum(a, b) {
    return a + b;
  }
}

const myClassInstance = new MyClass();
myClassInstance.calculateSum(5, 10); // 输出:"Function calculateSum returned 15"

4. 跟踪函数调用

想知道什么时候、以什么参数调用了某个函数吗?装饰器可以满足你的愿望!它们允许你记录函数的调用,为你提供宝贵的洞察力。

function logFunctionCall(target, propertyKey, descriptor) {
  const originalMethod = descriptor.value;

  descriptor.value = function(...args) {
    console.log(`Function ${propertyKey} called with arguments ${args}`);
    const result = originalMethod.apply(this, args);
    return result;
  };

  return descriptor;
}

class MyClass {
  @logFunctionCall
   greet(name) {
    console.log(`Hello, ${name}!`);
  }
}

const myClassInstance = new MyClass();
myClassInstance.greet("John"); // 输出:"Function greet called with arguments [John]"

5. 用装饰器装饰装饰器

没错,你可以叠加装饰器来创建更复杂的行为。这就像披萨的浇头,每层都增添了一份独特的风味。

function add(value) {
  return function(target, propertyKey, descriptor) {
    const originalMethod = descriptor.value;

    descriptor.value = function(...args) {
      const result = originalMethod.apply(this, args);
      return result + value;
    };

    return descriptor;
  };
}

function logFunctionReturnValue(target, propertyKey, descriptor) {
  const originalMethod = descriptor.value;

  descriptor.value = function(...args) {
    const result = originalMethod.apply(this, args);
    console.log(`Function ${propertyKey} returned ${result}`);
    return result;
  };

  return descriptor;
}

class MyClass {
  @add(10)
  @logFunctionReturnValue
  calculateSum(a, b) {
    return a + b;
  }
}

const myClassInstance = new MyClass();
const result = myClassInstance.calculateSum(5, 10); // 输出:"Function calculateSum returned 25"
console.log(`Result: ${result}`); // 输出:"Result: 25"

常见问题解答

1. 装饰器是 ES6 特性吗?

是的,JavaScript 装饰器是在 ES6 中引入的。

2. 我可以在 Node.js 和浏览器中使用装饰器吗?

是的,Node.js 和所有支持 ES6 的浏览器都支持装饰器。

3. 装饰器可以用于类和函数吗?

是的,装饰器可以用于类和函数的属性、方法和参数。

4. 我可以在编译时应用装饰器吗?

是的,使用 Babel 或 TypeScript 等工具,你可以将装饰器编译成普通 JavaScript。

5. 装饰器有性能影响吗?

是的,装饰器可能会导致一些性能开销,但通常可以忽略不计。