typescript的裝飾器使用

//不帶參數的裝飾器
function logClass(target: any) {
    var original = target;
    function construct(constructor, args) {
        var c: any = function () {
            return constructor.apply(this.args);   
        }
        c.prototype = constructor.prototype;
        return new c();
    }
    var f: any = function (...args) {
        console.log("New:" + original.name);
        return construct(original, args);
    }
    f.prototype = original.prototype;
    return f;
}
//類裝飾器,帶有參數的
function logClass2(option:string) {
    return function (target: any) {
        console.log("option:"+option);
        var original = target;
        function construct(constructor, args) {
            var c: any = function () {
                return constructor.apply(this.args);   
            }
            c.prototype = constructor.prototype;
            return new c();
        }
        var f: any = function (...args) {
            console.log("New:" + original.name);
            return construct(original, args);
        }
        f.prototype = original.prototype;
        return f; 
    }
}
//方法裝飾器
function logMethod(target: any, key: string, descriptor: any) {
    var originalMethod = descriptor.value;//保留原方法的引用
    descriptor.value = function (...args: any[]) {
        var a = args.map(a => JSON.stringify(a)).join();//將方法參數轉爲字符串
        var result = originalMethod.apply(this, args);//執行方法,獲得其返回值
        var r = JSON.stringify(result);//將返回值轉爲字符串
        console.log(`Call:${key}(${a}) => ${r}`);
        return result;
    }
    return descriptor;//返回編輯後的屬性描述對象
}
//屬性裝飾器
function logProperty(target: any,key:string) {
    var _val = this[key];//屬性值
    var getter = function () {
        console.log(`Get:${key} => ${_val}`);
        return _val;
    }
    var setter = function (newVal) {
        console.log(`Set:${key} => ${newVal}`);
        _val = newVal;
    }
    //刪除屬性,在嚴格模式下,若是對象是不可配置的,將會拋出一個錯誤。不然返回false
    if (delete this[key]) {
        Object.defineProperty(target, key, {
            get: getter,
            set: setter,
            enumerable: true,
            configurable:true
        })
    }
}
//參數裝飾器
function addMetadata(target: any, key: string, index: number){
    var metadataKey = `_log_${key}_parameters`;
    if (Array.isArray(target[metadataKey])) {
        target[metadataKey].push(index);
    } else {
        target[metadataKey] = [index];
    }
}
//讀取經過參數裝飾器添加的元數據,在執行時,不在展現全部參數,而是僅打印被裝飾的參數
function readMetadata(target: any, key: string, descriptor: any) {
    var originMethod = descriptor.value;
    descriptor.value = function (...args: any[]) {
        var metadataKey = `_log_${key}_parameters`;
        var indices = target[metadataKey];
        if (Array.isArray(indices)) {
            for (var i = 0; i < args.length; i++){
                if (indices.indexOf(i) !== -1) {
                    var arg = args[i];
                    var argStr = JSON.stringify(arg) || arg.toString();
                    console.log(`${key} arg[${i}]:${argStr}`);
                }
            }
            var result = originMethod.apply(this, args);
            return result;
        }
        return descriptor;
    }
}
@logClass
@logClass2("option value")
class Person {
    public name: string;
    @logProperty
    public surname: string;
    constructor(name: string, surname: string){
        this.name = name;
        this.surname = surname;
    }
    @readMetadata
    @logMethod
    say(@addMetadata st:string):string {
        console.log(this.name + "-->" + this.surname + " says :"+st);
        return this.name + "-->" + this.surname + " says :"+st;
    }
}
var me = new Person("raa", "jan");
me.surname = "hello1";
var n = me.surname;
me.say("hello");
相關文章
相關標籤/搜索