import angular from 'angular';
export const Before = (beforeFn) => (target, key, descriptor) => {
const fn = descriptor.value;
if (!angular.isFunction(fn)) {
throw new SyntaxError('Only functions can be @Before');
}
if (!angular.isFunction(beforeFn)) {
throw new SyntaxError('Only function can be pass to @Before');
}
return {
...descriptor,
value(...args) {
args = beforeFn.apply(this, args) || args;
return fn.apply(this, args);
}
};
};
export const After = (afterFn) => (target, key, descriptor) => {
const fn = descriptor.value;
if (!angular.isFunction(fn)) {
throw new SyntaxError('Only functions can be @After');
}
if (!angular.isFunction(afterFn)) {
throw new SyntaxError('Only function can be pass to @After');
}
return {
...descriptor,
value(...args) {
const result = fun.apply(this, args);
return fn.apply(this, args.unshift(result)) || result;
}
};
};
ES 装饰器在 AngularJS 1.x 中的使用
准备
关于 ES 装饰器(decorator) 这个特性,就不在这里详细的介绍了: 更多内容大家可以参考javascript-decorators
简单的总结一下: ES 的装饰器可以装饰类和类的方法(也可以装饰对象的方法):
1.装饰类的方法
2.装饰类
关于装饰器如何传参,参考上面提到的资料。
使用
因为现有产品需要切换成 ES6(当然这里不单指 ES6 的特性) 在公司 AngularJS1.x 与 ES6 的编码风格中,对 controller 的使用,已经全面使用 class 去实现,这为使用装饰器创造了条件。
1.声明依赖注入
AngularJS 依赖注入显示声明, 可以很好的利用装饰器。请看实现:
当然还有更好的实现,这个大家可以参看 angular-es-utils 中的 inject 实现,非常的巧妙。
如果考虑到继承的情况,angular-es-utils 中的 inject 就不合适了。 另外该 Inject 返回了新的 class 这样会导致一块使用的装饰器,无法获取原构造函数的信息。
最终方案,使用 Proxy 修改 constructor,自动将注入的服务挂载到 controller prototype 上
2.$apply
该实现依赖 angular-es-utils
3.$timeout
4.路由配置
使用 UI-Router 去实现应用中的路由,使用装饰器将路由配置与 controller class 进行绑定,当 Angular 声明 module 时,读取对应的路由配置进行路由设置。
将配置存入一个公共对象中,以 class 名称作为 key(也可以使用 Reflect.defineProperty 看你的浏览支持情况)
封装 AngularJS module 方法,当初始化 module 时,设置路由, 根据 AngularJS + ES6 风格指南,顺便不对外提供 factory 和 filter 方法
5.Mixin
除了使用继承外, 为了简化 controller, 将其它功能通过 Mixin 的方式混入 controller class 中。
6.Before/After
在 AngularJS1.x 结合 ES6 规范中已经弃用了 filter/service/factory 具体原因参考规范中No Service/Filter !!。 $provide.decorator 已经没有应用场景了。此时需要扩展一个 util 类或对象的方法,除了继承外,也可以使用装饰器进行扩展。
7.其他功能
类似 Debounce Bind 等功能,非常有用。这些都可以参考 core-decorators.js
以上装饰器的实现,请参考 https://github.com/hjzheng/angular-utils
最后
装饰器特性不仅可以在不改变原有类或方法的前提下,增加新的功能和特性,另外还可以简化代码的写法,对于编码效率提升非常有用。