zoukankan      html  css  js  c++  java
  • ts class 装饰器

    当多个装饰器应用于一个声明上,从上至下调用,从下而上执行

    function a() {
      console.log("调用 a");
    
      return function (target: any) {
        console.log("执行 a");
      };
    }
    
    function b() {
      console.log("调用 b");
      return function (target: any) {
        console.log("执行 b");
      };
    }
    
    @a()
    @b()
    class Ajanuw {}
    
    λ ts-node index.ts
    调用 a
    调用 b
    执行 b
    执行 a
    

    传递参数

    function info(opt: { username: string; age: number; email: string }) {
      return function (target: any) {
        target.username = opt.username;
        target.age = opt.age;
        target.email = opt.email;
      };
    }
    
    @info({
      username: "ajanuw",
      age: 14,
      email: "123@sina.com",
    })
    class Ajanuw {
      constructor() {}
    }
    const a = <any>Ajanuw;
    console.log(a.username, a.age, a.email);
    console.log(Ajanuw.prototype.constructor["username"]); // ajanuw
    

    es 的装饰器

    let l = console.log
    
    function klass(value) {
        return target => {
            // l(value) // api
            // l(target) // 对象
        }
    }
    
    function prop(value) {
        return function (target, key, des) { // target 对于静态成员来说是类的构造函数,对于实例成员是类的原型对象
            // l(value) // username
            // l(target, key, des) // 对象,属性名,属性描述符
        }
    }
    
    function func(value) {
        return function (target, key, des) { // target 对于静态成员来说是类的构造函数,对于实例成员是类的原型对象
            // l(value) // function
            // l(key) // 函数名 show
            // l(des.value) // show函数, 可以改写
            // des.value = function(){
            //     l('hello')
            // }
        }
    }
    
    function Body(target) {
        // l( target ) // undefined
    }
    
    @klass('api')
    class Ajanuw {
        @prop('username') name = 'ajanuw'
    
        @func('function')
        show(@Body body) {
            l(body)
        }
    }
    
    new Ajanuw().show()
    

    重载构造函数

    function classDecorator<T extends { new (...args: any[]): {} }>(
      constructor: T
    ) {
      return class extends constructor {
        newProperty = "new property";
        hello = "override";
      };
    }
    
    @classDecorator
    class Greeter {
      constructor(public hello: string) {}
    }
    var g = new Greeter("world");
    console.log(g.hello); // override
    

    参数装饰器

    import "reflect-metadata";
    
    const requiredMetadataKey = Symbol("required");
    const bodyMetadataKey = Symbol("body");
    
    function required(
      target: Object,
      propertyKey: string | symbol,
      parameterIndex: number
    ) {
      let existingRequiredParameters: number[] =
        Reflect.getOwnMetadata(requiredMetadataKey, target, propertyKey) || [];
      existingRequiredParameters.push(parameterIndex);
      Reflect.defineMetadata(
        requiredMetadataKey,
        existingRequiredParameters,
        target,
        propertyKey
      );
    }
    
    function Body(key: string): any {
      return function (target: any, propertyKey: string, parameterIndex: number) {
        let existingRequiredParameters: any[] =
          Reflect.getOwnMetadata(bodyMetadataKey, target, propertyKey) || [];
    
        existingRequiredParameters.push({ parameterIndex, key });
    
        // 注入元数据
        Reflect.defineMetadata(
          bodyMetadataKey,
          existingRequiredParameters,
          target,
          propertyKey
        );
      };
    }
    
    function validate(
      target: any,
      propertyName: string,
      descriptor: TypedPropertyDescriptor<any>
    ) {
      let method = descriptor.value;
    
      // 重写value
      descriptor.value = function () {
        let requiredParameters: number[] = Reflect.getOwnMetadata(
          requiredMetadataKey,
          target,
          propertyName
        );
    
        if (requiredParameters) {
          for (let parameterIndex of requiredParameters) {
            if (
              parameterIndex >= arguments.length ||
              arguments[parameterIndex] === undefined
            ) {
              throw new Error("Missing required argument.");
            }
          }
        }
    
        // 获取目标对象上提供的元数据键的元数据值
        Reflect.getOwnMetadata(bodyMetadataKey, target, propertyName)?.forEach(
          (it: any) => {
            // 重写参数
            arguments[it.parameterIndex] = arguments[it.parameterIndex][it.key];
          }
        );
    
        return method?.apply(this, arguments);
      };
    }
    
    class Greeter {
      @validate
      greet(@required @Body("name") name: any): any {
        console.log("Hello " + name); // Hello xxxx
      }
    }
    
    const g = new Greeter();
    g.greet({ name: "xxxx" });
    
  • 相关阅读:
    gridview列前加复选框需要注意的一点
    为什么日历控件放在panel无法显示出来
    表格翻页
    The SDK platform-tools version ((21)) is too old to check APIs compiled with API 23
    win7怎么安装和启动 jboss
    (转)如何制作nodejs,npm “绿色”安装包
    Can't use Subversion command line client: svn
    (转)Android自定义属性时format选项( <attr format="reference" name="background" /> )
    本地拒绝服务漏洞修复建议
    (转)Android 读取联系人(详细)
  • 原文地址:https://www.cnblogs.com/ajanuw/p/8934150.html
Copyright © 2011-2022 走看看