设为首页 加入收藏

TOP

Javascript装饰器的妙用(五)
2018-07-13 06:06:56 】 浏览:322
Tags:Javascript 装饰 妙用
@instance
  method2 = () => {}


  // 静态成员
  @static
  static method3 () {}
  @static
  static method4 = () => {}
}


function instance(target) {
  console.log(target.constructor === Model)
}


function static(target) {
  console.log(target === Model)
}


函数,访问器,和属性装饰器三者之间的区别


函数


首先是函数,函数装饰器的返回值会默认作为属性的value描述符存在,如果返回值为undefined则会忽略,使用之前的descriptor引用作为函数的描述符。
所以针对我们最开始的统计耗时的逻辑可以这么来做:


class Model {
  @log1
  getData1() {}
  @log2
  getData2() {}
}


// 方案一,返回新的value描述符
function log1(tag, name, descriptor) {
  return {
    ...descriptor,
    value(...args) {
      let start = new Date().valueOf()
      try {
        return descriptor.value.apply(this, args)
      } finally {
        let end = new Date().valueOf()
        console.log(`start: ${start} end: ${end} consume: ${end - start}`)
      }
    }
  }
}


// 方案二、修改现有描述符
function log2(tag, name, descriptor) {
  let func = descriptor.value // 先获取之前的函数


  // 修改对应的value
  descriptor.value = function (...args) {
    let start = new Date().valueOf()
    try {
      return func.apply(this, args)
    } finally {
      let end = new Date().valueOf()
      console.log(`start: ${start} end: ${end} consume: ${end - start}`)
    }
  }
}


访问器


访问器就是添加有get、set前缀的函数,用于控制属性的赋值及取值操作,在使用上与函数没有什么区别,甚至在返回值的处理上也没有什么区别。
只不过我们需要按照规定设置对应的get或者set描述符罢了:


class Modal {
  _name = 'Niko'


  @prefix
  get name() { return this._name }
}


function prefix(target, name, descriptor) {
  return {
    ...descriptor,
    get () {
      return `wrap_${this._name}`
    }
  }
}


console.log(new Modal().name) // wrap_Niko


属性


对于属性的装饰器,是没有返回descriptor的,并且装饰器函数的返回值也会被忽略掉,如果我们想要修改某一个静态属性,则需要自己获取descriptor:


class Modal {
  @prefix
  static name1 = 'Niko'
}


function prefix(target, name) {
  let descriptor = Object.getOwnPropertyDescriptor(target, name)


  Object.defineProperty(target, name, {
    ...descriptor,
    value: `wrap_${descriptor.value}`
  })
}


console.log(Modal.name1) // wrap_Niko


对于一个实例的属性,则没有直接修改的方案,不过我们可以结合着一些其他装饰器来曲线救国。


比如,我们有一个类,会传入姓名和年龄作为初始化的参数,然后我们要针对这两个参数设置对应的格式校验:


const validateConf = {} // 存储校验信息


@validator
class Person {
  @validate('string')
  name
  @validate('number')
  age


  constructor(name, age) {
    this.name = name
    this.age = age
  }
}


function validator(constructor) {
  return class extends constructor {
    constructor(...args) {
      super(...args)


      // 遍历所有的校验信息进行验证
      for (let [key, type] of Object.entries(validateConf)) {
        if (typeof this[key] !== type) throw new Error(`${key} must be ${type}`)
      }
    }
  }
}


function validate(type) {
  return function (target, name, descriptor) {
    // 向全局对象中传入要校验的属性名及类型
    validateConf[name] = type
  }
}


new Person('Niko', '18')  // throw new error: [age must be number]


首先,在类上边添加装饰器@validator,然后在需要校验的两个参数上添加@validate装饰器,两个装饰器用来向一个全局对象传入信息,来记录哪些属性是需要进行

首页 上一页 2 3 4 5 6 7 下一页 尾页 5/7/7
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇u-boot-1.1.6第1阶段分析之make s.. 下一篇Python 字节码介绍

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目