ECMAScript Decorators– Decorators
What is the Decorators
- Decorators can change the properties and behavior of class methods and class instance fields, giving us the flexibility to implement them dynamically using simpler syntax, noninvasive. — For example, if you add a cover to your phone, it doesn’t affect the phone’s original functions such as calling and charging
Application scenarios
- A classic use of Decorators is AOP programming, such as “logging systems,” which record the behavior of a system by adding logging sessions without affecting the functionality of the original system
- More abstractly, you can think of it as a layer of filters for data streams, so typical uses of AOP include security checking, caching, debugging, persistence, and so on.
The principle of
- The nature of Decorators is to take advantage of ES5’s Object.defineProperty property. These three parameters are identical to the Object.defineProperty parameter and therefore cannot be changed
- The object must be. This could be a native JavaScript object (that is, a user-defined object or a built-in object) or a DOM object.
- Propertyname required. A string containing the name of the property
- Descriptor required. Property descriptor. It can be for data attributes or accessor attributes.
- For example
var myObj = {
myPropOne: 1,
myPropTwo: 2
};
// modify property descriptor
Object.defineProperty( myObj, 'myPropOne', {
writable: false// Allow this property to change enumerable:false// Allow keys to be enumerated, in other wordsfor inKeys () does not output any key 64x:false// Whether the target attribute can be deleted or whether the attribute can be modified again});Copy the code
Application, for example,
- Class methods @ readonly
class User {
constructor( firstname, lastName ) {
this.firstname = firstname;
this.lastName = lastName;
}
@readonly
getFullName() {
return this.firstname + ' ' + this.lastName;
}
}
// create instance
let user = new User( 'John'.'Doe'); console.log( user.getFullName() ); / / one day I accidentally override this method to the User. The prototype. GetFullName =function() {
return 'HACKED! '; } // Print HACKED! // Method 1 is this the best solution? Object.defineproperty (user.prototype,'getFullName', {
writable: false}); // Add this method to the decorated method getFullNamefunction readonly( target, property, descriptor ) {
descriptor.writable = false;
return descriptor;
}
Copy the code
- Class method @log Logs are printed
function log( logMessage ) {
// return decorator function
return function ( target, property, descriptor ) {
// save original value, which is method (function)
let originalMethod = descriptor.value;
// replace method implementation
descriptor.value = function( ...args ) {
console.log( '[LOG]'.logMessage );
// here, call original method
// `this` points to the instance
returnoriginalMethod.call( this, ... args ); };return descriptor;
}
}
class User {
constructor( firstname, lastName ) {
this.firstname = firstname;
this.lastName = lastName;
}
@log('calling getFullName method on User class')
getFullName() {
return this.firstname + ' ' + this.lastName;
}
}
var user = new User( 'John'.'Doe' );
console.log( user.getFullName() );
Copy the code
- Class attribute case conversion
Initializer function is used internally by Babel to create the value of the property descriptor for object propertiesfunction toCase( CASE = 'lower' ) {
return function ( target, name, descriptor ) {
let initValue = descriptor.initializer();
descriptor.initializer = function() {return ( CASE == 'lower')? initValue.toLowerCase() : initValue.toUpperCase(); }return descriptor;
}
}
class User {
@toCase( 'upper' )
firstName = 'default_first_name';
lastName = 'default_last_name';
constructor( firstName, lastName ) {
if( firstName ) this.firstName = firstName;
if( lastName ) this.lastName = lastName;
}
getFullName() {
return this.firstName + ' ' + this.lastName;
}
}
console.log( new User() );
Copy the code
- Class decorator
function withLoginStatus( UserRef ) {
returnclass extends UserRef { constructor( ... args ) { super( ... args ); this.isLoggedIn =false;
}
setLoggedIn() {
this.isLoggedIn = true; } } } @withLoginStatus class User { constructor( firstName, lastName ) { this.firstName = firstName; this.lastName = lastName; }}let user = new User( 'John'.'Doe' );
console.log( 'Before ===> ', user );
// set logged in
user.setLoggedIn();
console.log( 'After ===> ', user );
Copy the code
Babel is installed in
- Online conversion link (if you cannot open the web page, you need to turn over the wall)
- Build the Babel install
3. NPM install babel-core babel-plugin-transform-decorators 4 Babel-plugin-transform-decorators-legacy --save-dev."plugins": [
"transform-decorators-legacy"]}Copy the code
Refer to the link
- ECMAScript Decorators– Decorators
- ES7 Decorator Decorator pattern
- Ruan Yifeng — decorator