npm install --save-dev @babel/plugin-proposal-decorators2.配置 .babelrc
{ "plugins": [ ["@babel/plugin-proposal-decorators", { "legacy": true }], ] }Babel 版本 ≤ 6.x
npm install --save-dev @babel/plugin-proposal-decorators2.配置 .babelrc
{ "plugins": ["transform-decorators-legacy"] }使用方法
@classDecorator class TargetClass { // 类 @fieldDecorator targetField = 0; // 类实例属性 @funDecorator targetFun() { } // 类方法 @accessorDecorator get targetGetFun() { } // 类访问器 }如果一个对象使用多个装饰器,那么执行顺序是什么呢?
function decorator1() { console.log('decorator1'); return function decFn1(targetClass) { console.log('decFn1'); return targetClass; }; } function decorator2() { console.log('decorator2'); return function decFn2(targetClass) { console.log('decFn2'); return targetClass; }; }执行顺序:
类访问器(公共、私有和静态)
var num = 0; function add () { num ++; } @add function fn() {}在这个例子中,我们想要在执行后让 num 等于 1,但其实结果并不是这样,因为函数提升,实际上代码是这样执行的:
function add () { num ++; } @add function fn() {} var num; num = 0;如果一定要装饰函数的话,可以采用高阶函数的形式,这篇文章主要讲装饰器,有关高阶函数就不在此赘述了,不了解的小伙伴们可自行查阅资料哈~
function decorator(...args) { args.forEach((arg, index) => { console.log(`参数${index}`, arg); }); } @decorator class TargetClass { } console.log('targetClass:', TargetClass);打印结果如下:
// 堆代码 duidaima.com function returnStr(targetClass) { return 'hello world~'; } function returnClass(targetClass) { return targetClass; } @returnStr class ClassA { } @returnClass class ClassB { } console.log('ClassA:', ClassA); console.log('ClassB:', ClassB);结果如下:
@decorator class TargetClass { } // 等同于 class TargetClass { } TargetClass = decorator(TargetClass) || TargetClass;所以说,装饰器的第一个参数就是要装饰的类,它的功能就是对类进行处理。
function addAttribute(targetClass) { targetClass.isUseDecorator = true; } @addAttribute class TargetClass { } console.log(TargetClass.isUseDecorator); // true在这个例子中,我们定义了 addAttribute 的装饰器,用于对 TargetClass 添加 isUseDecorator 标记,这个用法就跟 Java 中的注解比较相似,仅仅是对目标类型打上一些标记。
function addAttribute(content) { return function decFn(targetClass) { targetClass.content = content; return targetClass; }; } @addAttribute('这是内容~~~') class TargetClass { } console.log(TargetClass.content); // 这是内容~~~我们看到 TargetClass 通过 addAttribute 的装饰,添加了 content 这个属性,并且可以向 addAttribute 传参来给 content 属性赋值,这种使用方法使装饰器变得更加灵活。
function decorator(targetClass) { targetClass.prototype.decFun = function () { console.log('这里是装饰器 decorator 添加的原型方法 decFun~'); }; } @decorator class TargetClass { } const targetClass = new TargetClass(); console.log(targetClass); targetClass.decFun();结果如下:
// connect class App extends React.Component {} export default connect(mapStateToProps, mapDispatchToProps)(App); // 等同于 @connect(mapStateToProps, mapDispatchToProps) export default class App extends React.Component {} // Form.create const WrappedApp = Form.create()(App); // 等同于 @Form.create() class App extends React.Component {}
function decorator(...args) { args.forEach((arg, index) => { console.log(`参数${index}`, arg); }); console.log('****************'); } class TargetClass { @decorator field = 0; @decorator fn() { } @decorator get getFn() { } } const targetOne = new TargetClass(); console.log(targetOne.field, Object.getOwnPropertyDescriptor(targetOne, 'field'));结果如下:
function readonly(target, name, descriptor) { descriptor.writable = false; return descriptor; } class Person { @readonly name = 'zhangsan'; } const person = new Person(); console.log(person.name, Object.getOwnPropertyDescriptor(person, 'name'));打印结果如下:
function changeName(target, name, descriptor) { descriptor.value = 'lisi'; return descriptor; } class Person { @changeName name = 'zhangsan'; } const person = new Person(); // 等同于 class Person { name = 'zhangsan'; } const person = new Person(); Object.defineProperty(person, 'name', { value: 'lisi', });
... export default class CompOne extends Component { ... getData = async () => { // 调用后端接口 const data = await request('/xxx', { params: { id: '123', // 不同组件传参不同 }, }); this.setState({ data }); } render() { ... return ( <div> ... 我是组件一: {data} ... </div> ) } }遇到这种情况,我们就可以用装饰器解决呀~
// 装饰器 function getData(params) { return (Comp) => { class WrapperComponent extends Component { ... getData = async () => { const data = await request('/xxx', { params, }); this.setState({ data }); } render() { ... return ( <Comp data={data} /> ) } } return Comp; } } // 组件 ... @getData({ id: '123' }) export default class index extends Component { ... render() { ... const data = this.props.data; // 直接从 this.props 中获取想要的数据 return ( <div> ... 我是组件一: {data} ... </div> ) } }总结