装饰器是一种特殊类型的声明,它能够被附加到类声明,方法,访问符,属性或者参数上。装饰器使用@expression 这种形式,expression 求值后必须为一个函数,他会在运行时被调用,被装饰的生命信息作为参数传入。
例如,要一个@fn 装饰器,要定义一个函数
function fn(target){
// do somethinng.....
}
通过一些@方法名可以对一些对象进行装饰然后返回一个被包装过的对象,可以装饰的对象包括,类,对象,方法等
1,装饰器工厂
要制定装饰器首先要有一个装饰器工厂函数,装饰器工厂就是一个简单的函数,他返回一个表达式,以供装饰器在运行时是调用
function color (value: string) { //装饰器工厂
return function (target) { //装饰器
//do something target and value
}
}
2,装饰器组合
多个装饰器可以应用到同一个声明上,操作步骤 A,从上之下依次对装饰器表达式求值 B,求值结果会被当做成函数,从下至上依次被调用
如果使用装饰器工厂 求值结果为:装饰器工厂函数内从上至下依次调用,装饰器内从下至上依次调用
function f ( ) {
console.log(‘f() : evaluated’)
return function (target, value){
console.log(‘f(): called’)
}
}
function g ( ) {
console.log(‘g() : evaluated’)
return function (target, value){
console.log(‘g(): called’)
}
}
Class c {
@f()
@g()
method(){}
}
结果打印: 装饰器函数外部由上向下依次执行,内部由下向上依次执行
f(): evaluated
g() : evaluated
g(): called
f(): called
3,装饰器求值
类中不同声明上的装饰器求值顺序 。。。。。。略
4,类装饰器:
类装饰器在类声明之前被声明,类装饰器用于类构造函数,可以修改或替换类定义。
类装饰器表达式在运行时被当做函数调用,类的构造函数作为其唯一的参数。 装饰器的第一个函数参数就是所要要装饰的目标类 。 例如:class类构造函数就是 fn 的唯一参数。
@fn
class newFN{
//do something...
}
如果类装饰器返回一个值,他会使用提供的构造函数类替换类的声明。
简单的装饰器
1,装饰器函数
//装饰器函数
const classDecorator = (target: { isShow: boolean; }) => {
target.isShow = false;
}
//class 构造函数
@classDecorator
class Mine extends Component{
isShow: string; // 声明
constructor(){
super()
}
componentDidMount(){
//do something...
}
render(){
return (
<div>
我的页面
</div>
)
}
}
console.log(Mine.isShow) // false 装饰器传入的 boolean
export default Mine;
//一个函数不够可以外层封装一个函数。就是装饰器工厂
const classDecorator = (flag: boolean) => { //flag为调用装饰器传入的参数
return function(target: { isShow: boolean; }) { //target 为使用该装饰器的构造类
target.isShow = flag;
}
}
@classDecorator(true)
class Mine extends Component{
isShow:string;
}
console.log(Mine.isShow) //true 装饰器所传的 flag
重载构造函数
/**
1,类构造函数中声明未赋值,在装饰器函数中变量赋值,最终为装饰器函数返回的值
2,类构造函数中声明且赋值,在装饰器函数中变量赋值,最终为装饰器函数返回的值
3,类构造函数中声明且赋值,在装饰器函数中变量未赋值,最终为构造函数返回的值
**/
const classDecorator = (constructor) => {
return class extends constructor {
newPropoty = "new propoty"
hello = "hello"
}
}
@classDecorator
class Greeter {
propoty = "propoty";
hello: string;
constructor(m: string){
this.hello = m
}
}
console.log(new Greeter('hello2')) //
前面的例子是为类添加一个静态属性,如果想添加实例属性,可以通过目标类的 prototype 对象操作。
export const classDecorator = (...message) => {
return function(target) {
Object.assign(target.prototype, ...message)
}
}
const Foo = {
foo() { console.log('foo') }
};
@classDecorator(Foo)
class Mine extends Component{
...
}
console.log(new Mine().foo()) //foo Foo对象内部的打印
//通过classDecorator 装饰器,将对象 Foo 添加到了Mine 实例上面.
5,方法装饰器
方法装饰器在运行时会被当做函数调用,传入 3 个参数
1,类的原型对象,
2,所要装饰的属性名
3,该属性的描述对象
//装饰器
export const decoratorFn = (target, name, descriptor) =>{
descriptor.isShow = true;
return descriptor;
}
class Mine extends Component {
gretting: string;
constructor(m){
super(m)
this.gretting = m;
}
//方法装饰器
@decoratorFn
great(){
return 'hello,' + 'this.gretting'
}
}
当装饰器@decoratorFn 被调用时,就会修改属性descriptor的 isShow 值