DarkFlame / blog

blog for me
2 stars 0 forks source link

es6修饰器decorator学习总结 #3

Open DarkFlame opened 6 years ago

DarkFlame commented 6 years ago

修饰器总结

直接修饰类

@testable
class MyTestableClass {
  // ...
}

function testable(target) { //target,就是会被修饰的类。
  target.isTestable = true;
}

MyTestableClass.isTestable // true

上面代码直接修饰 类MyTestableClass,给他加了一个静态属性isTestable, 也就是说,修饰器是一个对类进行处理的函数。修饰器函数的第一个参数,就是所要修饰的目标类

修饰方法


function readonly(target, name, descriptor){
  //方法修饰器的,第一个参数是所要修饰的目标对象,即类的实例(这不同于类的修饰,那种情况时target参数指的是类本身);
  //第二个参数是所要修饰的属性名,第三个参数是该属性的描述对象
  // 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);

class Person {
  @readonly
  name() { return `${this.first} ${this.last}` }
}

上面代码修饰器(readonly)会修改属性的描述对象(descriptor),然后被修改的描述对象再用来定义属性。

core-decorators.js 第三方修饰库的使用

  1. @autobind 自动绑定方法中的this到原始对象
  2. @readonly 修饰属性或方法只读
  3. @override 检查子类是否覆盖父类的同名方法(参数必须一致) 不正确会报错
  4. @deprecate 修饰器会在控制台输出一条警告,表示该方法已经废弃
  5. @time 方法执行的时间
  6. @enumerable 方法是否可枚举
  7. @nonenumerable 属性是否不可枚举
  8. @decorate 立即调用提供的函数,被修饰的函数作为参数,允许你其他库的方法去包裹方法

使用修饰器实现自动发布事件

我们可以使用修饰器,使得对象的方法被调用时,自动发出一个事件。postal.js

import postal from "postal/lib/postal.lodash";

export default function publish(topic,channel) {
    return function (target,name,descriptor) {
        const fn = descriptor.value;

        descriptor.value = function () {
            let value = fn.apply(this,arguments);
            postal.channel(channel || target.channel || "/").publish(topic,value);
        };
    };
}

var anotherSub = postal.subscribe({
    topic: "#",
    channel: "component",
    callback: function (data,envelope) {
        console.log(data,envelope)
    }
});

class FooComponent {
    @publish("foo.some.message","component")
    someMethod() {
        return {
            my: "data"
        };
    }

    @publish("foo.some.other","component")
    anotherMethod() {
        return {
            you: "asddata"
        };
    }
}

let foo = new FooComponent();

foo.someMethod() // 在"component"频道发布"foo.some.message"事件,附带的数据是{ my: "data" }
foo.anotherMethod() //

参考 阮老师