Adorner mode
What is an adorner?
Formerly known as decorator is translated into adorners can be understood as decorative decoration packaging and other means
The role in reality
A house can become more ornate and more functional through decoration
Similar to a mobile phone can be used alone but a lot of people are willing to home a protective cover to prevent the fall ...
The role of JS
Adorners can be said to solve the problem of sharing methods between different classes (can be seen as bridging the gap of inheritance).
A Python decorator is a function that takes another function, extending the behavior of the latter function without explic itly modifying it.
This is a very nice explanation for the decorator.
This concept is also introduced in future JavaScript, and Babel has a good support for him. If you're a crazy developer, you can use it with Babel.
Environment preparation
Adorners are currently not supported in the browser or Node and need to be converted to a supported version with Babel
Installing Babel
Follow the official website instructions to install:
npm install --save-dev babel-cli babel-preset-env
Write in. BABELRC:
{ "presets": ["env"]}
Follow the instructions to install the Babel-plugin-transform-decorators-legacy plugin:
. BABELRC:
{ "presets": ["env"], "plugins": ["transform-decorators-legacy"]}
So the preparation is done.
Begin
Let's look at the wording of an adorner.
class Boy{ @run speak (){ console.log('I can speak') }}function run () { console.log('I can run')}let tj = new Boy()tj.speak()// I can run // I can speak
@run is an adorner (in fact, a function) added to the Class attribute method (speak) that extends the speak of the class boy (running while speaking)
Adorners can not only decorate the class of methods can also decorate the class (but can not decorate the function, because the function exists variable elevation)
The adorner function accepts 3 parameters that are decorative objects, decorative properties, and descriptions of decorative properties
class Boy{ @run speak (){ console.log('I can speak') }}function run (target,key,descripter) { console.log(target,key,descripter)}let tj = new Boy()tj.speak()// Boy {} 'speak' { value: [Function: speak], writable: true, enumerable: false, configurable: true }I can speak
Let's look at one more example
class Math { @log add(a, b) { return a + b }}function log(target, name, descriptor) { var oldValue = descriptor.value descriptor.value = function() { console.log(`Calling ${name} with`, arguments) return oldValue.apply(target, arguments) } return descriptor}const math = new Math()// passed parameters should get logged nowmath.add(2, 4)// Calling add with { '0': 2, '1': 4 }
The equivalent of extending a console.log function on the original Add method without changing the original function (we can take the parameters and change him)
Parameters can also be passed through the adorner
function log(num) { return function(target, name, descriptor) { var oldValue = descriptor.value let _num = num || 0 descriptor.value = (...arg) => { arg[0] += _num console.log(`Calling${target}, ${name} with`, arg) return oldValue.apply(target, arg) } return descriptor }}class Math { constructor(a = 3, b = 4) { this.add(a, b) } @log(100) add(a, b) { return a + b }}const math = new Math()console.log(math)console.log(math.add(9,1))
We decorate the koa-router with decorators.
We want to extend more functionality to Koa-router, and it is good for readability maintainability and code elegance, such as:
export default class MovieRouter{ @get('/api/v0/movie') @auth() @log() ...}
Give way by doing some other preparation before you actually process your business (such as verifying that the user is logged on and then outputting the log)
For the above, let's start with a simple implementation
Const KOA = require (' Koa ') const APP = new Koa () const {Connect} = Require (' ... /db/index ') Const Mongoose = require (' Mongoose ') const SHIJUE = Mongoose.model (' Shijue ') const Router = require (' Koa-router ') Const ROUTER = new Router ()//Connection database void (Async () = {await connect ()}) () class Route {constructor () { This.app = App This.router = router} init () {Routermap.map (item=>{Router[item.method] (Item.path, item . Callback)}) App.use (Router.routes ()) App.use (Router.allowedmethods ())}}var routermap = []function Get (path) { return function (target, key, descriptor) {Routermap.push ({path, Target, method: ' Get ', Callback:target[key]}) re Turn descriptor}}var logtimes = 0function log () {return function (target, key, descriptor) {App.use (async function ( CTX, Next) {logtimes++ console.time (' ${logtimes}: ${ctx.method}-${ctx.url} ') await next () console.t Imeend (' ${logtimes}: ${ctx.method}-${ctx.url} ') Return descriptor}}}Class Shijuerouter {@get ('/api ') @log () Async Getshijue (CTX, Next) {//await ... return (Ctx.body = {code:0, d ATA: ' Shijue '})}}app.use (Router.routes ()) App.use (Router.allowedmethods ()) Async function Start () {var r = new Route () R.init () App.listen (3001, function (err) {if (err) {Console.log (err)} else {Console.log (' Startup succeeded: 3001 ') }})}start ()
Code comparison rough can be refined separation
and the realization of React-redux.
JavaScript Adorner mode