裝飾器(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();
})
複製代碼