美文网首页
JS的装饰器

JS的装饰器

作者: 王小滚 | 来源:发表于2019-04-08 19:36 被阅读0次

    什么是装饰器

    在面向对象(OOP)的设计模式中,decorator被称为装饰模式。我们在程序开发中,许多时候并不希望某个类天生就非常庞大,一次性包含许多职责。装饰者模式可以动态地给某个对象添加一些额外的功能,而不会影响从这个类中派生的其他对象。

    JS的装饰器

    为了更简便的使用装饰器模式,ES7引入了一个新的语法,依赖于 ES5 的Object.defineProperty方法。

    修饰器的用法

    类的装饰
    class A {}
    
    // 等同于
    
    class A {}
    A = decorator(A) || A;
    

    也就是说,装饰器是一个对类进行处理的函数。装饰器函数的第一个参数,就是所要修饰的目标类。
    如果觉得一个参数不够用,可以在装饰器外面再封装一层函数。

    function testable(isTestable) {
      return function(target) {
        target.isTestable = isTestable;
      }
    }
    
    @testable(true)
    class MyTestableClass {}
    MyTestableClass.isTestable // true
    
    @testable(false)
    class MyClass {}
    MyClass.isTestable // false
    
    

    简单来说JS 的装饰器可以用来“装饰”三种类型的对象:类的属性/方法、访问器、类本身

    针对属性/方法的装饰器
    class Person {
        @readonly
        name() { return `${this.first} ${this.last}` }
    }
    function readonly(target, name, descriptor){
      // 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);
    
    • 装饰器第一个参数是的原型对象,上例是 Person.prototype,装饰器的本意是要“装饰”类的实例,但是这个时候实例还没生成,所以只能去装饰原型(这不同于类的装饰,那种情况时target参数指的是类本身);
    • 第二个参数是 所要装饰的属性名
    • 第三个参数是 该属性的描述对象
    函数方法的装饰

    由于存在函数提升,使得修饰器不能用于函数。类是不会提升的,所以就没有这方面的问题。
    可以采用高阶函数的形式直接执行。

    function doSomething(name) {
      console.log('Hello, ' + name);
    }
    
    function loggingDecorator(wrapped) {
      return function() {
        console.log('Starting');
        const result = wrapped.apply(this, arguments);
        console.log('Finished');
        return result;
      }
    }
    
    const wrapped = loggingDecorator(doSomething);
    
    // decorator 外部可以包装一个函数,函数可以带参数
    function Decorator(type){
        /**
         * 这里是真正的 decorator
         * @target 装饰的属性所述的类的原型,注意,不是实例后的类。如果装饰的是 Car 的某个属性,这个 target 的值就是 Car.prototype
         * @name 装饰的属性的 key
         * @descriptor 装饰的对象的描述对象
         */
        return function (target, name, descriptor){
            // 以此可以获取实例化的时候此属性的默认值
            let v = descriptor.initializer && descriptor.initializer.call(this);
            // 返回一个新的描述对象,或者直接修改 descriptor 也可以
            return {
                enumerable: true,
                configurable: true,
                get: function() {
                    return v;
                },
                set: function(c) {
                    v = c;
                }
            }
        }
    }
    

    相关文章

      网友评论

          本文标题:JS的装饰器

          本文链接:https://www.haomeiwen.com/subject/keveiqtx.html