ES2015 + ES2016(装饰,理解,...)+ Angular 1.x组件

时间:2015-07-11 16:15:47

标签: javascript angularjs ecmascript-6 ecmascript-7

我正在开发一个使用Angular 1.x的Web应用程序架构,但仍然习惯于将事物粘合在一起。定义新组件非常简单:

class CustomComponent {
  constructor(dep1, dep2, dep3) {
    this.deps = { dep1, dep2, dep3 };
    /* app code */
  }

  /* link, compile, instance methods, template generators... */

  @readonly static $inject = ['dep1', 'dep2', 'dep3'];
}

我想做的是考虑注射问题 - 换句话说,我不想每次都写this.depsstatic $inject代码,而是拥有它自动生成 - 比方说,像ES7中的装饰器一样。然后代码将按以下方式显示:

@injectionFromCtorComponents
class MyClass {
  constructor (dep1, dep2, dep3) {
    /* app logic */
  }
}

现在,静态部分是可行的,尽管很难看:

const angularInjectAnnotationFromCtor = (target) => {
    let regexStr = `^function ${target.name}\\\((.*)\\\)[.\\s\\S]*}$`;
    let regex = new RegExp(regexStr, 'gm');
    let ctorArgsStr = target.prototype.constructor.toString().replace(regex, '\$1');
    let ctorArgs = ctorArgsStr.replace(/ /g, '').split(',');

    target.$inject = ctorArgs;
};

但是,在实例上保存构造函数依赖性要复杂得多。我想出了以下内容,尽管它充其量只是脆弱的:

const readonly = (target, key, descriptor) => Object.assign(descriptor, { writable: false });

class AngularComponent {
  constructor () {
    let ctorArgs = [...arguments];
    let argNames = ctorArgs.pop();

    // let's leave comprehensions out of this :)
    this.deps = 
      argNames.reduce((result, arg, idx) => Object.assign(result, ({ [arg]: ctorArgs[idx] })), {});
  }
}

@angularInjectAnnotationFromCtor
class MyClass extends AngularComponent {
    constructor (one, two, three) {
      super(one, two, three, MyClass.$inject);
    }
}

是的,这比我们开始时更糟糕......

那么问题是,有人可以建议更合理的解决方案吗?或者我们应该在未来几年内随时坐下来希望Chrome中的Proxies?

1 个答案:

答案 0 :(得分:1)

你想法的静态部分基本上就是没有$inject。这毫无意义。

我建议忘记这个想法或将参数传递给装饰者:

@inject('dep1', 'dep2', 'dep3')
class MyClass {
  constructor (dep1, dep2, dep3) {
    /* app logic */
  }
}

构造函数部分可以使用经典的装饰器模式完成:

function inject() {
  var dependencies = [...arguments];

  return function decorator(target) {
    target.$inject = dependencies;  

    return function() {
      this.deps = {};
      dependencies.forEach((dep, index) => {
        this.deps[dep] = arguments[index];
      });

      target.constructor.apply(arguments, this);
      return this;
    }
  }
}