插件——反向洋葱模型

173 阅读1分钟

假如让你开放插件,需要将上个插件的内容传入,然后将处理过后的内容传给下一个插件,要怎么实现呢?

function pluig1(Parser) {
  return class class1 extends Parser {
    constructor() {
      super()
      console.log('class1 实例化')
    }
      parse(program) {
        console.log(program)
        return(super.parse(program + 1))
      }
  }
}

function pluig2(Parser) {
  return class class2 extends Parser {
    constructor() {
      super()
      console.log('class2 实例化')
    }
      parse(program) {
        console.log(program)
        return(super.parse(program + 2))
      }
  }
}

const newParser = Parser.extend(pluig1, pluig2);

newParser.parse(3);

实现方式

首先定义一个Parser类,定义两个静态方法,注意静态方法能被继承

class Parser{
    static extend() {
    // ...
    }
    
    static create(input, options) {
    // ..
    }
    
    parse(program) {
        return program
  }
}

extend

注意插件的格式:接收上一个class,然后继承它,再返回继承的class

static extend() {
      var plugins = [], len = arguments.length;
      while ( len-- ) plugins[ len ] = arguments[ len ];

    var cls = this;
    for (var i = 0; i < plugins.length; i++) { cls = plugins[i](cls); }
    return cls
};

比如这是插件 class1,它继承了Parser,下一个插件class2,它继承了class1,那么原型链就形成了

Parser -> class1 -> class2

extend的最终结果是class2

parse

static create(input, options) {
    return new this(options, input).parse()
  };

此时class2有这两个静态方法,一个继承,一个创建实例。

然后执行newParser.parse(3),也就是class2.parse(3)

进入到static parse 里面,会新建class2的实例对象

新建class2的实例对象时,会顺着原型链依次新建 class1-Parser的实例对象

然后调用class2Instance.parse,将0传入,经过处理将结果2返回给class1Instance.parse

class1Instance.parse将处理结果3返回给Parser.parse

总结

acorn 就是用类似的方式写插件的,webpack loader 放在数组后面的先拿code也是这个原因