- Mastering Angular Components
- Gion Kunz
- 816字
- 2021-07-23 17:23:40
Decorators
Decorators are not part of the ECMAScript 6 specification, but they were proposed to the ECMAScript 7 standard for 2016. They provide us with a way to decorate classes and properties during design time. This allows a developer to use meta-annotations while writing classes, and declaratively attach functionality to the class and its properties.
Decorators are named after the decorator pattern that was initially described in the book Design Patterns: Elements of Reusable Object-Oriented Software, by Erich Gamma and his colleagues, also known as the Gang of Four (GoF).
The principle of decoration is that an existing procedure is intercepted and the decorator has the chance to either delegate, provide an alternative procedure, or do a mix of both:

Decorators in ECMAScript 7 can be used to annotate classes and class properties. Note that this also includes class methods, as class methods are also properties of the class prototype object. Decorators get defined as regular functions, and they can be attached to classes or class properties with the at symbol. Our decorator function will then be called with contextual information about the location of inclusion every time that the decorator is placed.
Let's take a look at a simple example that illustrates the use of a decorator:
function logAccess(obj, prop, descriptor) {
const delegate = descriptor.value;
descriptor.value = function() {
console.log(`${prop} was called!`);
return delegate.apply(this, arguments);
};
}
class MoneySafe {
@logAccess
openSafe() {
this.open = true;
}
}
const safe = new MoneySafe();
safe.openSafe(); // openSafe was called!
We have created a logAccess decorator that will log all function calls that are tagged with the decorator. If we look at the MoneySafe class, you can see that we have decorated the openSafe method with our logAccess decorator.
The logAccess decorator function will be executed for each annotated property within our code. This enables us to intercept the property definition of the given property. Let's take a look at the signature of our decorator function. Decorator functions that are placed on class properties will be called with the target object of the property definition as a first parameter. The second parameter is the actual property name that is defined, followed by the last parameter, which is the descriptor object that is supposed to be applied to the object.
The decorator gives us the opportunity to intercept the property definition. In our case, we use this ability to exchange the descriptor value (which is the annotated function) with a proxy function that will log the function call before calling the origin function (delegation). For simplification purposes, we've implemented a very simple yet incomplete function proxy. For real-world scenarios, it would be advisable to use a better proxy implementation, such as the ECMAScript 6 proxy object.
Decorators are a great feature to leverage aspect-oriented concepts and declaratively add behavior to our code at design time.
Let's look at a second example where we use an alternative way to declare and use decorators. We can treat decorators like function expressions where our decorator function is rewritten as a factory function. This form of usage is especially useful when you need to pass along configuration to the decorator, which is made available in the decorator factory function:
function delay(time) {
return function(obj, prop, descriptor) {
const delegate = descriptor.value;
descriptor.value = function() {
const context = this;
const args = arguments;
return new Promise(function(success) {
setTimeout(function() {
success(delegate.apply(context, arguments));
}, time);
});
};
};
}
class Doer {
@delay(1000)
doItLater() {
console.log('I did it!');
}
}
const doer = new Doer();
doer.doItLater(); // I did it! (after 1 second)
We have now learned how ECMAScript 7 decorators can help you write declarative code that has an aspect-oriented twist to it. This simplifies development a lot because we can now think of behavior that we add to our classes during design time when we actually think about the class as a whole and write the initial stub of the class.
Decorators in TypeScript are slightly different than the decorators from ECMAScript 7. They are not limited to classes and class properties, but they can be placed on parameters within the class methods. This allows you to annotate function parameters, which can be useful in some cases:
class TypeScriptClass {
constructor(@ParameterDecorator() param) {}
}
Angular uses this feature to simplify dependency injection on class constructors. As all directive, component, and service classes get instantiated from Angular dependency injection and not by us directly, these annotations help Angular find the correct dependencies. For this use case, function parameter decorators actually make a lot of sense.
- 網絡故障現場處理實踐(第4版)
- HCNA網絡技術
- Drush User’s Guide
- Building RESTful Web Services with Spring 5(Second Edition)
- 物聯網技術與應用
- 數字調制解調技術的MATLAB與FPGA實現:Altera/Verilog版(第2版)
- IPv6網絡切片:使能千行百業新體驗
- 異構蜂窩網絡關鍵理論與技術
- 5G技術核心與增強:從R15到R17
- Hands-On Docker for Microservices with Python
- 網絡安全之道
- 數字王國里的虛擬人:技術、商業與法律解讀
- 區塊鏈技術與應用:打造分布式商業新生態
- 算力網絡:云網融合2.0時代的網絡架構與關鍵技術
- Migrating to Drupal7