野兽'' 2019-04-23 3678浏览量
临时起的兴趣,想写一篇关于ts decorator的文章,就花小半天整理了一下...
这东西,在ES2017里好像也有... 文档的话看这里。
因为临时,也没想写太多文字介绍,带少许文字说明直接开撸代码吧。
本文通过ts编译后的decorator代码解释一番装饰器是什么?能做什么?有什么好处?
编译后代码是这样的,带注释:
var __decorate =
(this && this.__decorate) ||
function(decorators, target, key, desc) {
// c 参数长度
// r ? c < 3 则是target,否则先判断desc为null的话则将desc取target的key属性的描述,再否则便是desc了
// d 预留使用
var c = arguments.length,
r =
c < 3
? target
: desc === null
? (desc = Object.getOwnPropertyDescriptor(target, key))
: desc,
d;
// 下面文字解释,这仅是个甩锅的行为
if (typeof Reflect === "object" && typeof Reflect.decorate === "function")
r = Reflect.decorate(decorators, target, key, desc);
// 循环 decorators 并每次赋值给 d,并且判断值
else
for (var i = decorators.length - 1; i >= 0; i--)
if ((d = decorators[i]))
// c < 3 ,用 r 作为 decorators[i] 的入参执行;
// c > 3 ,target, key, r 作为 decorators[i] 的入参执行;
// c === 3,target, key 作为 decorators[i] 的入参执行。
// 如果执行无返回结果, r = r;。
r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
// 如果 c > 3 && r , 修改 target ,返回 r
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
从代码里可以看出,最终结果要么是用decorator执行target,从而改变一些什么东西;要么就是使用Object.defineProperty来对target来做操作,代码就几行,用处确不小...具体的执行过程结合下面的两个例子会更容易理解。
值得一提的是,关于代码里的Reflect原本以为是这个 sec-reflect-object 里的方法,但可惜不是;
然后猜测是Typescript的实现,翻了Typescript/tsc.js的代码(如果打不开链接就从 node_modules 下看吧),发现也不是,再去查 stackoverflow 的解释,是这样的 what-is-reflect-decorate-in-js-code-transpiled-from-ts
大致说是ts希望把这个锅甩给ES来补,到时候ts的else里的代码便是polyfill了
以下面的 decorator 和 class 作为例子解释
// ts 代码
function show(target: any) {
console.log(target);
target.prototype.showMe = (name: string) => {
console.log("show me :", name);
};
}
interface IShow {
showMe?(name: string): any;
}
@show
class Show implements IShow {
showMe(name: string) {}
}
const shoow = new Show();
shoow.showMe("ys");
// 编译后的js
// decorator ,简单的打印,并且修改方法
function show(target) {
console.log(target);
target.prototype.showMe = function(name) {
console.log("show me :", name);
};
}
// class Shoow
var Shoow = (function() {
function Shoow() {}
Shoow.prototype.showMe = function(name) {};
// decorators 为[show],target 为 Shoow
Shoow = __decorate([show], Shoow);
return Shoow;
})();
var shooow = new Shoow();
shooow.showMe("ys");
// output : show me : ys
理解一下执行步骤:
一个不够?再来一个?这次在里面返回一个函数试试?
// ts代码
function logger1(config?) {
return function(target, key: string, descriptor: PropertyDescriptor) {
const _value = descriptor.value;
if (typeof _value === "function") {
descriptor.value = (...args) => {
console.log(`logger1-begin : ${config.level}`);
const res = _value.apply(target, args);
console.log(`logger1-end`);
return res;
};
}
return descriptor;
};
}
function logger2(config?) {
return function(target, key: string, descriptor: PropertyDescriptor) {
const _value = descriptor.value;
if (typeof _value === "function") {
descriptor.value = (...args) => {
console.log(`logger2-begin : ${config.level}`);
const res = _value.apply(target, args);
console.log(`logger2-end`);
return res;
};
}
return descriptor;
};
}
interface IShow {
showMe?(name: string): any;
}
class Show implements IShow {
@logger1({ level: "info" })
@logger2({ level: "error" })
showMe(name: string) {
console.log("show me :", name);
}
}
const shoow = new Show();
shoow.showMe("ys");
// output 这里手动加个缩进,这时候showMe方法已经经过多次包裹
// logger1-begin : info
// logger2-begin : error
// show me : ys
// logger2-end
// logger1-end
再来看看执行步骤:
装饰器给你带来什么欢乐?简单列几个最明显的优点,其他在运用中各自提取每日份的快乐去吧...
// 日常
dosomething(){
consol.log('start')
// some thing
console.log('end')
}
// 使用装饰器
@logger(logConfig?)
dosomething();
// 日常多层HOC
class MyComponent extends Component{
// ..
}
connect(mapFn)(
MyHoc(someMapFn)(
Form.create(fieldsMapFn)(MyComponent)
)
)
// 使用装饰器
@connect(mapFn)
@MyHoc(someMapFn)
@FormFields(fieldsMapFn)
class MyComponent extends Component{
// ..
}
export default MyComponent;
AOP,了解一下
版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。
集结各类场景实战经验,助你开发运维畅行无忧