decorator作为一个提案,经过了多次修改,还未正式发布,不过在实际编程过程中,装饰器已经有了很多的应用。装饰器很受欢迎的主要原因是其借鉴了java中注解的概念,让代码结构性和可读性大大增强。
装饰器的意义:更好地解释类的相关属性和概念,将不同的功能归类区分,便于维护和扩展。
demo:
@Component({
tag: 'my-component',
styleUrl: 'my-component.scss'
})
export class MyComponent {
@Prop() first: string;
@Prop() last: string;
@State() isVisible: boolean = true;
render() {
return (
<p>Hello, my name is {this.first} {this.last}</p>
);
}
}
上面的代码很好的看出当前类的一些介绍。
装饰器的分类:
1,类的装饰 (接受参数target)
语法:
function testable(target) {
//doSomething
}
@testable
class MyTestableClass {}
2,方法的装饰
function readonly(target, name, descriptor){ //这里的target不同于类的装饰,指的是要装饰类的prototype
// descriptor对象原来的值如下
// {
// value: specifiedFunction,
// enumerable: false,
// configurable: true,
// writable: true
// };
descriptor.writable = false;
return descriptor;
}
说明:方法装饰器的target不同于类的装饰,指的是要装饰类的
实例:
class Person {
@nonenumerable
get kidCount() { return this.children.length; }
}
function nonenumerable(target, name, descriptor) {
console.log(target)
descriptor.enumerable = false;
return descriptor;
}
装饰器的高级用法:
从装饰器的使用上可以看出,在使用装饰器时,并没有直接执行装饰器,只是指定装饰器,因此装饰器可以写成高阶函数的形式,在函数里返回一个装饰器。在指定装饰器时直接执行外层函数,返回一个待执行的装饰器。
实例:
//类的装饰器
function testable(isTestable) {
return function(target) {
target.isTestable = isTestable;
}
}
@testable(true)
class MyTestableClass {}
MyTestableClass.isTestable // true
@testable(false)
class MyClass {}
MyClass.isTestable // false
//方法装饰器
function dec(id){
console.log('evaluated', id);
return (target, property, descriptor) => console.log('executed', id);
}
class Example {
@dec(1)
@dec(2)
method(){}
}
一个很重要的注意事项:
装饰器不能用于函数,因为函数存在提升。(存在函数提升的原因是js解释器在对js代码进行词法分析时,会先去进行函数的定义,对于函数表达式不会存在变量提升也是基于该原因,具体可以去研究js执行上下文队列的相关知识)
实例:
var counter = 0;
var add = function () {
counter++;
};
@add
function foo() {
}
实际上运行时:(上下文入栈顺序)
@add
function foo() {
}
var counter;
var add;
counter = 0;
add = function () {
counter++;
};
mixin
自定义的混入对象方法的函数,可以根据实际业务场景进行封装。
比如:
export function mixins(...list) {
return function (target) {
Object.assign(target.prototype, ...list);
};
}
几个重要的库:
1,core-decorators.js
core-decorators.js是一个第三方模块,提供了几个常见的装饰器,通过它可以更好地理解装饰器。
比如:@readonly
import { readonly } from 'core-decorators';
class Meal {
@readonly
entree = 'steak';
}
var dinner = new Meal();
dinner.entree = 'salmon';
2,Trait
traits-decorator这个第三方模块这个模块提供的traits
装饰器,不仅可以接受对象,还可以接受 ES6 类作为参数。
实例:
import { traits } from 'traits-decorator';
class TFoo {
foo() { console.log('foo') }
}
const TBar = {
bar() { console.log('bar') }
};
@traits(TFoo, TBar)
class MyClass { }
let obj = new MyClass();
obj.foo() // foo
obj.bar() // bar