Javascript JS TS将decorator应用于所有方法/枚举类方法

Javascript JS TS将decorator应用于所有方法/枚举类方法,javascript,typescript,decorator,Javascript,Typescript,Decorator,我想将decorator函数应用于类中的所有方法,以便替换: class User { @log delete() {} @log create() {} @log update() {} } 与 创建一个类装饰器并枚举目标原型上的属性 对于每个财产: 获取属性描述符 确保是为了一种方法 将描述符值包装到一个新函数中,该函数记录有关方法调用的信息 将修改后的属性描述符重新定义回属性 修改属性描述符很重要,因为您希望确保您的装饰器能够与修改属性

我想将decorator函数应用于类中的所有方法,以便替换:

class User {
    @log
    delete() {}

    @log
    create() {}

    @log
    update() {}
}


创建一个类装饰器并枚举目标原型上的属性

对于每个财产:

  • 获取属性描述符
  • 确保是为了一种方法
  • 将描述符值包装到一个新函数中,该函数记录有关方法调用的信息
  • 将修改后的属性描述符重新定义回属性
  • 修改属性描述符很重要,因为您希望确保您的装饰器能够与修改属性描述符的其他装饰器很好地协同工作

    function log(target: Function) {
        for (const propertyName of Object.keys(target.prototype)) {
            const descriptor = Object.getOwnPropertyDescriptor(target.prototype, propertyName);
            const isMethod = descriptor.value instanceof Function;
            if (!isMethod)
                continue;
    
            const originalMethod = descriptor.value;
            descriptor.value = function (...args: any[]) {
                console.log("The method args are: " + JSON.stringify(args));
                const result = originalMethod.apply(this, args);
                console.log("The return value is: " + result);
                return result;
            };
    
            Object.defineProperty(target.prototype, propertyName, descriptor);        
        }
    }
    
    基类方法

    如果您希望这也会影响基类方法,那么您可能需要以下内容:

    function log(target: Function) {
        for (const propertyName in target.prototype) {
            const propertyValue = target.prototype[propertyName];
            const isMethod = propertyValue instanceof Function;
            if (!isMethod)
                continue;
    
            const descriptor = getMethodDescriptor(propertyName);
            const originalMethod = descriptor.value;
            descriptor.value = function (...args: any[]) {
                console.log("The method args are: " + JSON.stringify(args));
                const result = originalMethod.apply(this, args);
                console.log("The return value is: " + result);
                return result;
            };
    
            Object.defineProperty(target.prototype, propertyName, descriptor);        
        }
    
        function getMethodDescriptor(propertyName: string): TypedPropertyDescriptor<any> {
            if (target.prototype.hasOwnProperty(propertyName))
                return Object.getOwnPropertyDescriptor(target.prototype, propertyName);
    
            // create a new property descriptor for the base class' method 
            return {
                configurable: true,
                enumerable: true,
                writable: true,
                value: target.prototype[propertyName]
            };
        }
    }
    
    功能日志(目标:功能){
    for(target.prototype中的constPropertyName){
    constPropertyValue=target.prototype[propertyName];
    const isMethod=函数的propertyValue实例;
    如果(!isMethod)
    继续;
    常量描述符=getMethodDescriptor(propertyName);
    const originalMethod=descriptor.value;
    descriptor.value=函数(…参数:任意[]){
    log(“方法args是:”+JSON.stringify(args));
    const result=originalMethod.apply(此参数为args);
    log(“返回值为:“+result”);
    返回结果;
    };
    Object.defineProperty(target.prototype、propertyName、descriptor);
    }
    函数getMethodDescriptor(propertyName:string):TypedPropertyDescriptor{
    if(target.prototype.hasOwnProperty(propertyName))
    返回Object.getOwnPropertyDescriptor(target.prototype,propertyName);
    //为基类的方法创建新的属性描述符
    返回{
    对,,
    可枚举:正确,
    可写:对,
    值:target.prototype[propertyName]
    };
    }
    }
    
    事实上,对我来说,只有当我将你编写的
    target.prototype
    替换为
    target
    @MaorRefaeli在这个问题中,修饰师被放在类上,所以
    target
    是类函数,
    target.prototype
    是类原型。因此,如果指定了
    target
    ,那么它将查看静态方法,而不是原型上的实例方法。如果以ES2015而不是ES5为目标,此处的代码可能需要更改,因为以这种方式获取ES2015类的属性不起作用。。。无论如何,应该使用原型。你是对的:)我忘了提到我在静态类对象上使用了它。当编译目标不是ES5时,keys不起作用。getOwnPropertyNames(target.prototype)对我来说在其他所有目标中都运行良好。
    function log(target: Function) {
        for (const propertyName in target.prototype) {
            const propertyValue = target.prototype[propertyName];
            const isMethod = propertyValue instanceof Function;
            if (!isMethod)
                continue;
    
            const descriptor = getMethodDescriptor(propertyName);
            const originalMethod = descriptor.value;
            descriptor.value = function (...args: any[]) {
                console.log("The method args are: " + JSON.stringify(args));
                const result = originalMethod.apply(this, args);
                console.log("The return value is: " + result);
                return result;
            };
    
            Object.defineProperty(target.prototype, propertyName, descriptor);        
        }
    
        function getMethodDescriptor(propertyName: string): TypedPropertyDescriptor<any> {
            if (target.prototype.hasOwnProperty(propertyName))
                return Object.getOwnPropertyDescriptor(target.prototype, propertyName);
    
            // create a new property descriptor for the base class' method 
            return {
                configurable: true,
                enumerable: true,
                writable: true,
                value: target.prototype[propertyName]
            };
        }
    }