设为首页 加入收藏

TOP

Javascript装饰器的妙用(二)
2018-07-13 06:06:56 】 浏览:323
Tags:Javascript 装饰 妙用
descriptor = Object.getOwnPropertyDescriptor(target, key)


  Object.defineProperty(target, key, {
    ...descriptor,
    writable: false      // 设置属性不可被修改
  })
}


wrap(Model1, 'getData')



Model1.prototype.getData = 1 // 无效



可以看出,两个wrap函数中有不少重复的地方,而修改程序行为的逻辑,实际上依赖的是Object.defineProperty中传递的三个参数。
所以,我们针对wrap在进行一次修改,将其变为一个通用类的转换:


function wrap(decorator) {
  return function (Model, key) {
    let target = Model.prototype
    let dscriptor = Object.getOwnPropertyDescriptor(target, key)


    decorator(target, key, descriptor)
  }
}


let log = function (target, key, descriptor) {
  // 将修改后的函数重新定义到原型链上
  Object.defineProperty(target, key, {
    ...descriptor,
    value: function (...arg) {
      let start = new Date().valueOf()
      try {
        return descriptor.value.apply(this, arg) // 调用之前的函数
      } finally {
        let end = new Date().valueOf()
        console.log(`start: ${start} end: ${end} consume: ${end - start}`)
      }
    }
  })
}


let seal = function (target, key, descriptor) {
  Object.defineProperty(target, key, {
    ...descriptor,
    writable: false
  })
}


// 参数的转换处理
log = wrap(log)
seal = warp(seal)


// 添加耗时统计
log(Model1, 'getData')
log(Model2, 'getData')


// 设置属性不可被修改
seal(Model1, 'getData')


到了这一步以后,我们就可以称log和seal为装饰器了,可以很方便的让我们对一些函数添加行为。
而拆分出来的这些功能可以用于未来可能会有需要的地方,而不用重新开发一遍相同的逻辑。


Class 中的作用


就像上边提到了,现阶段在JS中继承多个Class是一件头疼的事情,没有直接的语法能够继承多个 Class。


class A { say () { return 1 } }
class B { hi () { return 2 } }
class C extends A, B {}        // Error
class C extends A extends B {} // Error


// 这样才是可以的
class C {}
for (let key of Object.getOwnPropertyNames(A.prototype)) {
  if (key === 'constructor') continue
  Object.defineProperty(C.prototype, key, Object.getOwnPropertyDescriptor(A.prototype, key))
}
for (let key of Object.getOwnPropertyNames(B.prototype)) {
  if (key === 'constructor') continue
  Object.defineProperty(C.prototype, key, Object.getOwnPropertyDescriptor(B.prototype, key))
}


let c = new C()
console.log(c.say(), c.hi()) // 1, 2


所以,在React中就有了一个mixin的概念,用来将多个Class的功能复制到一个新的Class上。
大致思路就是上边列出来的,但是这个mixin是React中内置的一个操作,我们可以将其转换为更接近装饰器的实现。
在不修改原Class的情况下,将其他Class的属性复制过来:


function mixin(constructor) {
  return function (...args) {
    for (let arg of args) {
      for (let key of Object.getOwnPropertyNames(arg.prototype)) {
        if (key === 'constructor') continue // 跳过构造函数
        Object.defineProperty(constructor.prototype, key, Object.getOwnPropertyDescriptor(arg.prototype, key))
      }
    }
  }
}


mixin(C)(A, B)


let c = new C()
console.log(c.say(), c.hi()) // 1, 2


以上,就是装饰器在函数、Class上的实现方法(至少目前是的),但是草案中还有一颗特别甜的语法糖,也就是@Decorator了。
能够帮你省去很多繁琐的步骤来用上装饰器。


@Decorator的使用方法


草案中的装饰器、或者可以说是TS实现的装饰器,将上边的两种进一步地封装,将其拆分成为更细的装饰器应用,目前支持以下几处使用:
1.Class
2.函数
3.get set访问器
4.实例属性、静态函数及属性
5.函数参数


@Decorator的语法规定比较简单,就是通过@符号后边跟一个装饰器函数的引用:


@tag
class A {
  @method
  hi () {}
}


function tag(constructor) {
  console.log(constructor === A) // true
}


function method(target) {
  console.log(target.construc

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

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目