装饰器(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方法能劫持另一个对象的方法,继承另一个对象的属性
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
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"&¶m_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();
})
复制代码