1. 程式人生 > >Decorator裝飾器

Decorator裝飾器

Decorator 修飾器

說明

由 ES2017 引入了這個功能,他是一個函式用來修改類的行為,解決了不同類之間共享方法的問題

修飾器對類的行為的改變是在程式碼編譯時發生的,而不是在執行時,本質就是編譯時執行的函式

由於存在變數提升,使得修飾器不能用於函式(包括建構函式),類不會提升所以不會有這個問題

基本使用


    @decorator  
    class Test {
        constructor(name) {
            this.name = name;
        }
    }

    function
decorator (target) {
// target 就是需要被修飾的類 target.prototype.getName = function () { console.log(this.name); } } const test = new Test('xiaobai'); test.getName(); // xiaobai

修飾器通過封裝後接受其他引數

    function addMethod(methods) {
        return function (target)
{
Object.assign(target.prototype, methods); } } const methods = { change: function () {console.log('change')}, add: function () {}, delete: function () {}, get: function () {} } @addMethod(methods) class Test {} const test = new
Test(); test.change(); // change

修飾器可以修飾類中的方法

作用在方法上的 decorator 接受的第一個引數是類的 prototype;作用到類上的 decorator 第一個引數表示類本身

Decorators 的本質是利用了 ES5 的 Object.defineProperty 屬性,所以它的三個引數:target name descriptor 跟 Object.defineProperty 的引數是一致的

Object.defineProperty 的引數詳解看這裡

  • target:需要修飾的類的原型 prototype
  • name: 需要修飾的類的屬性名或者方法名
  • descriptor:被修改的屬性的描述符
    • configurable:true | false 表示物件的屬性是否可以被刪除,以及除 writable 特性外的其他特性是否可以被修改
    • enumerable:true | false 定義被修改的屬性是否可以是可以列舉的
    • value:此屬性對應的值(數值、物件、函式等)
    • writable:true | false 是否可以重寫此屬性
    • initializer:如果修飾器修飾的是一個屬性不是方法,則會有這個屬性出現代替 value
    function log (target, name, descriptor) {
        // 保留舊的方法
        const tempFn = descriptor.value;

        // 重新定義方法
        descriptor.value = function () {
            console.log(`this is ${name} arguments: `, arguments);
            // 借用舊的方法
            return tempFn.apply(this, arguments);
        }

        return descriptor;
    }

    class Test {
        constructor() {
            this.list = []
        }

        @log
        add (...items) {
            this.list.push(...items);
        }
    }

    var test = new Test();
    test.add(12, 33, 222);
    // 修飾器列印的日誌
    // this is add arguments:  (3) [12, 33, 222, callee: (...), Symbol(Symbol.iterator): function]
    console.log(test); // {list: [12, 33, 222]}

修飾器修飾屬性

    function change(target, name, descriptor) {
        const tempVal = descriptor.initializer();
        console.log(descriptor.initializer);
        /*
            initializer 函式型別
            function initializer() {
                return 'def value';
            }
        */
        descriptor.initializer = function () {
            return 'change ' + tempVal;
        }
        return descriptor;
    }


    class Test {

        @change
        def = 'def value'
    }

    const test = new Test();
    console.log(test.def) // change def value

修飾器可以疊加使用

    function log (order) {
        return function (target, name, descriptor) {
            const tempFn = descriptor.value;

            descriptor.value = function () {
                console.log('decorator ' + order);
                return tempFn.apply(this, arguments);
            }

            return descriptor;
        }
    }

    class Test {
        constructor() {
            this.list = []
        }

        @log('top')
        @log('bottom')
        add (...items) {
            this.list.push(...items);
        }
    }

    var test = new Test();
    test.add(12, 33, 222);
    // decorator top | decorator bottom
    console.log(test); // {list: [12, 33, 222]}

更多文章