ES Decorators 的最新版本是 Stage 3,在该版本中,装饰器的特性得到了进一步的扩展和改进,其中一些重要的变化如下:
1. 私有属性装饰器
在 ES6 中,引入了类和私有属性的概念,但是对于私有属性,我们无法在其上应用装饰器。而在私有属性装饰器的引入之后,我们可以使用装饰器来扩展私有属性的功能,例如,为私有属性添加缓存、验证、事件处理等功能。
function privateProperty(target, key) {
const privateKey = Symbol(key);
Object.defineProperty(target, key, {
get() {
if (this.hasOwnProperty(privateKey)) {
return this[privateKey];
}
return undefined;
},
set(newValue) {
Object.defineProperty(this, privateKey, {
writable: true,
configurable: true,
enumerable: false,
value: newValue
});
},
enumerable: false,
configurable: false
});
}
class MyClass {
@privateProperty
myPrivateField;
constructor() {
this.myPrivateField = 'private value';
}
getMyPrivateField() {
return this.myPrivateField;
}
}
const myObject = new MyClass();
console.log(myObject.myPrivateField); // undefined
console.log(myObject.getMyPrivateField()); // 'private value'
2. 类表达式装饰器
在 ES6 中,我们可以使用 class 关键字来定义一个类,但是不能在类表达式上应用装饰器。而在类表达式装饰器的引入之后,我们可以使用装饰器来扩展类表达式的功能,例如,为类表达式添加日志、错误处理、性能监控等功能。
function log(target, name, descriptor) {
const original = descriptor.value;
descriptor.value = function(...args) {
console.log(`[${name}] called with arguments: ${JSON.stringify(args)}`);
const result = original.apply(this, args);
console.log(`[${name}] returned: ${JSON.stringify(result)}`);
return result;
};
return descriptor;
}
@log
class Calculator {
add(a, b) {
return a + b;
}
subtract(a, b) {
return a - b;
}
}
const calculator = new Calculator();
calculator.add(2, 3); // [add] called with arguments: [2,3], [add] returned: 5
calculator.subtract(5, 2); // [subtract] called with arguments: [5,2], [subtract] returned: 3
4. 装饰器组合
在 ES6 中,我们可以使用 @decorator 来装饰一个类、方法或属性,但是只能应用一个装饰器。而在装饰器组合的引入之后,我们可以使用多个 @decorator 来组合使用。
function upperCase(target, name, descriptor) {
const original = descriptor.value;
descriptor.value = function(...args) {
const result = original.apply(this, args);
if (typeof result === 'string') {
return result.toUpperCase();
}
return result;
}
return descriptor;
}
function reverse(target, name, descriptor) {
const original = descriptor.value;
descriptor.value = function(...args) {
const result = original.apply(this, args);
if (typeof result === 'string') {
return result.split('').reverse().join('');
}
return result;
}
return descriptor;
}
class MyClass {
@upperCase
@reverse
sayHello() {
return 'hello world';
}
}
const myClass = new MyClass();
console.log(myClass.sayHello()); // dlrow OLLEh
6. 装饰器工厂的返回值
该特性允许装饰器工厂返回任何类型的值,例如:
function repeat(numRepeats) {
return function decoratorRepeat(target, key, descriptor) {
const originalMethod = descriptor.value;
descriptor.value = function(...args) {
for (let i = 0; i < numRepeats; i++) {
originalMethod.apply(this, args);
}
}
return descriptor;
}
}
class Greeting {
@repeat(3)
sayHello(name) {
console.log(`Hello, ${name}!`);
}
}
const greeting = new Greeting();
greeting.sayHello('John');