NodeJs Decorator装饰器

装饰器的做用

装饰器(Decorator)是一个函数,用来修改类的行为。这是ES7的一个提案,目前Babel转码器已经支持。api

console.log('start decorate.js');
//对类的装饰 为类添加一个静态属性
@addCountry
class tank_1 {
  // ...
}
//
function addCountry(target) {
  target.country = "Chinese";
}

console.log(tank_1.country);

//对类的实例装饰 添加实例属性 经过目标类的prototype对象操做

@addLevel
class tank_2 {

}

function addLevel(target){
  target.prototype.Level=10;
}
console.log(new tank_2().Level)


//若是以为一个参数不够用,能够在修饰器外面再封装一层函数。
@addTankType("轻坦")
class tank_3{

}
function addTankType(tankType){
return function(target){
  target.tankType=tankType
}
}
console.log(tank_3.tankType);

//对类中的方法的修饰
/* 修饰器函数readonly一共能够接受三个参数。 function readonly(target, name, descriptor){ // descriptor对象原来的值以下 // { // value: specifiedFunction, // enumerable: false, // configurable: true, // writable: true // }; descriptor.writable = false; return descriptor; } readonly(Person.prototype, 'name', descriptor); // 相似于 Object.defineProperty(Person.prototype, 'name', descriptor); 修饰器第一个参数是类的原型对象,上例是Person.prototype,修饰器的本意是要“修饰”类的实例,可是这个时候实例还没生成,因此只能去修饰原型(这不一样于类的修饰,那种状况时target参数指的是类自己);第二个参数是所要修饰的属性名,第三个参数是该属性的描述对象。 */
class tank_4{

  @shoot
  shoot(a,b){
    console.log("shoot"+a+" "+b)
  }
}

function shoot(target,name,descriptor){
  //descriptor.value:表示tank_4对象的方法shoot(a,b)
  var oldValue = descriptor.value;

  console.log(descriptor.value);
  descriptor.value = function() {
    console.log(`Calling ${name} with`, arguments);
    return oldValue.apply(this, arguments);
  };
  return descriptor;
}

new tank_4().shoot(1,2);



复制代码

apply的做用

apply方法能劫持另一个对象的方法,继承另一个对象的属性


function Person(name,age){   //定义一个类,人类 
    this.name=name;     //名字 
    this.age=age;       //年龄 
    this.sayhello=function(){alert("hello")};
} 
function Print(){            //显示类的属性 
    this.funcName="Print"; 
    this.show=function(){      
        var msg=[];
        for(var key in this){ 
            if(typeof(this[key])!="function"){
                msg.push([key,":",this[key]].join(""));
            }
        } 
        alert(msg.join(" "));
    };
} 
function Student(name,age,grade,school){    //学生类 
    Person.apply(this,arguments);
    Print.apply(this,arguments);
    this.grade=grade;                //年级 
    this.school=school;                 //学校 
} 
var p1=new Person("jake",10);
p1.sayhello();
var s1=new Student("tom",13,6,"清华小学");
s1.show();
s1.sayhello();
alert(s1.funcName);

复制代码

学生类原本不具有任何方法,可是在Person.apply(this,arguments)后,数组

他就具有了Person类的sayhello方法和全部属性。app

在Print.apply(this,arguments)后就自动获得了show()方法koa

装饰器Route

const Router = require('koa-router')
const {resolve} = require('path')
const _ = require('lodash')
const glob = require('glob')
const R = require('ramda')
const Joi = require('joi');

const symbolPrefix = Symbol('prefix')
const routerMap = new Map()

const isArray = c => _.isArray(c)
  ? c
  : [c]

import Msg from "../utils/msg"
import url from 'url';
import mongoose from "mongoose";

const clientModel = mongoose.model("client")

export class Route {
  constructor(app, apiPath) {
    this.app = app
    this.apiPath = apiPath
    this.router = new Router()
  }

  init() {
    //获取路由文件 require("");
    glob.sync(resolve(this.apiPath, './**/*.js')).forEach(require)

    //获取校验参数文件
    glob.sync(resolve(resolve(__dirname, '../check_param'), './**/*.js')).forEach(require)

    for (let [conf, controller] of routerMap) {
      console.log(controller)
      const controllers = isArray(controller)
      let prefixPath = conf.target.symbolPrefix;
      if (prefixPath)
        prefixPath = normalizePath(prefixPath)
      const routerPath = prefixPath + conf.path
      this.router[conf.method](routerPath, ...controllers) //对应的路由地址 找到对应的方法
    }

    this.app.use(this.router.routes())
    this.app.use(this.router.allowedMethods())
  }
}

const normalizePath = path => path.startsWith('/')
  ? path
  : `/${path}`
//对function的装饰 
//conf :{method:"post",path:"/getUser"} 
//target:class User, key:为方法名getUser descriptor:class User的keyfunction 具体实现
const router = conf => (target, key, descriptor) => {
  conf.path = normalizePath(conf.path)
  console.log(conf);
  routerMap.set({
    target: target,
    method: conf.method,
    path: conf.path
  }, target[key])
}
//对类的装饰 用于初始化路由
export const ctrl = path => target => (target.prototype.symbolPrefix = path)
/* const ctrl=function(path){ return function(target){ target.prototype.symbolPrefix=path; } }*/
//对方法的装饰 用户初始化路由
export const get = path => router({method: 'get', path: path})
/* const get_1 =function(path){ return function (target, key, descriptor) { path = normalizePath(path) console.log(conf); routerMap.set({target: target,method: "get",path: path}, target[key]);//<路由类,以及路由类对应的方法> } }*/
export const post = path => router({method: 'post', path: path})

const decorate = (target, key, descriptor, middleware) => {
  //let [target, key, descriptor] = args

  target[key] = isArray(target[key])

  target[key].unshift(middleware)
  //console.log(descriptor);
  // return descriptor
}

//const convert = middleware => (...args) => decorate(args, middleware)
//对方法的装饰 用于添加中间件
const convert = function(middleware) {
  return function(target, key, descriptor) {
    //decorate(args, middleware)
    target[key] = isArray(target[key])

    target[key].unshift(middleware)
  }
}

export const required=function(rules){
  return function(middleware){
    return function(target,key,descriptor){
    target[key] = isArray(target[key])
    target[key].unshift(middleware)
    return descriptor
    }
  }
}
export const check = rules => convert(async (ctx, next) => {
  let errors = []
  if (!Array.isArray(rules)) {
    console.error("@check rules必须为数组类型");
  }
  if (rules.length < 3) {
    console.error("@check 必须传递三个参数");
  }
  let param_position = rules[0];
  if(param_position!="body"&&param_position!="query"){
    console.error("param_position should be \"body\" or query");
  }
  //console.log(param_position);
  let check_file = rules[1];
  //console.log(check_file);
  let check_func = rules[2];
  //console.log(check_func);
  let content = ctx.request[param_position];
  //console.log(content);

  // console.log(check_func);
  let schema = null;
  try {
    schema = require(resolve(__dirname, '../check_param/' + check_file))[check_func];
  } catch (error) {
    console.error("@check 参数传递有误");
    console.error(error);
  }
  //console.log(schema);
  const result = Joi.validate(content, schema);
  //console.log(result.error);
  if (result.error) {

    ctx.body = new Msg().paramError(result.error.details[0].message);
    return;
  }

  await next()
})

export const auth=()=>convert(async(ctx,next)=>{
  let decoded=ctx.state.decoded;
  let {client_id}=decoded;
  let _client=await clientModel.findOne({client_id:client_id}).lean();
  if(_client&&_client.admin_type==0){
  //没有权限访问
  ctx.body=new Msg().send_403();
  return;
  }
  await next();
})

复制代码
相关文章
相关标签/搜索