11

我一直在阅读 JavaScript 中的装饰器,并认为我已经掌握了基本前提。

装饰器是函数,它们作为一个或多个参数接收它们应该装饰的内容,并返回结果。

但是我@withStyles在一个 React Boiler Plate 项目中遇到了一个装饰性的实现,我不明白它是如何工作的。

import React, { Component, PropTypes } from 'react';

function withStyles(...styles) {
  return (BaseComponent) => class StyledComponent extends Component {
    static contextTypes = {
      insertCss: PropTypes.func.isRequired,
    };

    componentWillMount() {
      this.removeCss = this.context.insertCss.apply(undefined, styles);
    }

    componentWillUnmount() {
      this.removeCss();
    }

    render() {
      return <BaseComponent {...this.props} />;
    }
  };
}

export default withStyles;

一个用例是

import s from './MyComponentStyle.scss';

@withStyles(s)
class MyComponent extends Component {

}

这是如何运作的?

4

1 回答 1

14

类装饰器可以用作工厂函数。例如:

function myDecorator(value) {
   return function(target) {
      target.myProperty = value;
   }
}

@myDecorator('myValue')
class MyClass { }

在您的示例中,工厂函数返回包装原始类的构造函数。此函数用于创建对象而不是原始类。在您的情况下,它处理事件(componentWillMount, componentWillUnmount)以插入/删除 css 并使用其道具呈现原始组件。

这是一个非常简单的示例,演示了装饰器如何覆盖原始构造函数:

function myDecorator(name) {
   return (target) => class Wrapper {
       sayHello() {
           const targetObject = new target();
           console.log(`wrapper ${name} says hello`);
           targetObject.sayHello();
       }
       wrapperMethod() {
           console.log('calling wrapper function');
       }
   };
}

@myDecorator('Jack')
class MyClass {
    sayHello() {
        console.log('original says hello');
    }
    myMethod() {
       console.log('calling original function');
    }
}

var obj = new MyClass();

obj.sayHello();
//wrapper Jack says hello
//original says hello

obj.wrapperMethod();
//calling wrapper function

obj.myMethod();
//TypeError: obj.myMethod is not a function
于 2016-01-13T13:19:09.800 回答