ES7装饰器decorators解析
1,首先思考一个问题,在哪种情况下需要用到装饰器,装饰器的作用是什么?
我自己的答案:装饰器可以修改类里面的属性,或是新增类的属性。在需要就类原本的功能扩展新功能时会用到装饰器。我当时理解到这里时不禁产生了一个疑问,如果只是这样,要加新功能直接在类上面加就是了,为什么还要弄个装饰器出来呢?解释是,自己定义的类,想怎么改属性当然就能怎么改了,但是继承的类呢,比如说有一个你自己写的react组件,它继承于component,你现在想修改它的componentUpdate生命周期方法,给它加上一些功能,并且不会影响到其他继承了这个类的实例,那么答案就很明显了,这就是装饰器的用处。
2,装饰器用法
2.1 装饰类
第一步:全局定义一个方法
function test(target) {
target.xx = '艾欧尼亚'
}
这里的target就是接收要修饰的对象的一个形参,也就是下面的类Lei
第二步: 装饰一个类
@test
class Lei {
xx = '芜湖'
}
console.log(Lei.xx) // '艾欧尼亚'
这样,就修改了类的属性xx了。这种修饰写法等同于 test(Lei),函数调用完后会返回一个根据test(target)函数加工过的类Lei,这种有点类似于高阶组件的写法,高阶组件就是一个构造函数定义的组件,这个函数接收一个组件B作为参数,对这个组件做过某些处理后再返回一个包含组件B的类方式定义的组件出来。
修饰的时候也可以传参,写法如下,后面提到的装饰类的属性要是要传参也可以这样写
function test(xx) {
return function(target) {
target.name = xx;
}
}
@test('幸运儿')
class Lei {
name = '倒霉蛋'
}
console.log(Lei.name ) // '幸运儿'
2.2 装饰类的属性
这里也分为两步,就一起写了
function test(target, say, descriptor) {
// target参数代表类的原型对象,也就是Lei.prototype
// say参数代表要装饰的属性名
// descriptor参数是一个对象,如下
// {
// value: say函数的函数地址,也就是要装饰的属性的值
// enumerable: false 该属性是否允许枚举(就是被遍历到)
// configurable: true 该属性是控制descriptor能否被修改
// writable: true 该属性控制此属性的值是否可修改
//}
//在这里可以通过descriptor参数对say方法进行一些功能上的扩展,比如先将
//descriptor.value的值赋值给变量a,a此时就相当于函数say(),然后再将一个实现扩展功能的函数赋值
//给变量b,且在这个方法中调用a(), ps: 如果这个方法中需要修改this指向,可以用call或apply
// 这样做就可以保留原方法,且扩展新功能了
//最后再返回这个方法结合enumerable等属性的一个对象
return descriptor
}
class Lei {
state = { xx: 'Hi' }
@test
say(this.state.xx) { }
}
3,装饰器原理
基于es5的object.defineProperty方法,这个方法本来就是修改某个对象的某个属性的值,所以结合装饰器的功能,很好理解,但具体是基于这个方法做了怎样的处理实现了装饰器这种写法,就有待深究了。。。。
ps: 注意es版本,低版本使用babel转义