#装饰器模式

只关心拓展出来的那部分新功能如何实现

#ES 中的装饰器还在提案

// 装饰器函数,它的第一个参数是目标类
function classDecorator(target) {
  target.hasDecorator = true
  return target
}

// 将装饰器“安装”到Button类上
@classDecorator
class Button {
  // Button类的相关逻辑
}

// 验证装饰器是否生效
console.log('Button 是否被装饰了:', Button.hasDecorator)

也可以用同样的@语法糖去装饰类里面的方法

function funcDecorator(target, name, descriptor) {
  let originalMethod = descriptor.value
  descriptor.value = function () {
    console.log('我是Func的装饰器逻辑')
    return originalMethod.apply(this, arguments)
  }
  return descriptor
}

class Button {
  @funcDecorator
  onClick() {
    console.log('我是Func的原有逻辑')
  }
}

目前需要 babel 或者 ts 打包后才可以生效

#装饰器语法糖

本质就是函数传参和调用

  • 类装饰器 就是将类传入类装饰器函数

  • 类方法装饰器 就是将(类的原型对象,方法名,方法属性的描述对象)传入类方法装饰器函数

#生产实践

拓展功能,那么就能用装饰器来改写

例如:

  • React 的 高阶组件 HOC
  • Redux 的 connect 函数

#高阶组件 HOC

高阶组件就是一个函数,且该函数接受一个组件作为参数,并返回一个新的组件

const BorderHoc = (WrappedComponent) =>
  class extends Component {
    render() {
      return (
        <div style={{ border: 'solid 1px red' }}>
          <WrappedComponent />
        </div>
      )
    }
  }
export default borderHoc
import BorderHoc from './BorderHoc'

// 用BorderHoc装饰目标组件
@BorderHoc
class TargetComponent extends React.Component {
  render() {
    // 目标组件具体的业务逻辑
  }
}

// export出去的其实是一个被包裹后的组件
export default TargetComponent

#Redux 的 connect

Redux 使用时需要调用 connect 方法来把状态和组件绑在一起

class App extends Component {
  render() {
    // App的业务逻辑
  }
}

function mapStateToProps(state) {
  // 假设App的状态对应状态树上的app节点
  return state.app
}

function mapDispatchToProps(dispatch) {
  // 这段看不懂也没关系,下面会有解释。重点理解connect的调用即可
  return bindActionCreators(action, dispatch)
}

// 把App组件与Redux绑在一起
export default connect(mapStateToProps, mapDispatchToProps)(App)
import connect from './connect.js'

@connect
export default class App extends Component {
  render() {
    // App的业务逻辑
  }
}

#小结

不改变旧的来进行拓展