对Descriptor的理解

2018-08-28  本文已影响0人  笑笑料料

修饰类

target参数指的是,构造函数(类)Person,而不是实例。如果想对实例进行修饰,可以通过target.prototype对实例的属性进行修饰

const init = (target) => {
  target.nickName = 'person_name'
  target.prototype.nickName = 'kitty'
}

@init
class Person {
  nickName = 'native_name'
}

const cat = new Person()

console.log('Person', Person.nickName)  // 'Person person_name'
console.log('instance', cat.nickName) // 'instance native_name'

修饰方法

const log = (target, name, descriptor) => {
// 这里的this为undefined
  const oldAdd = descriptor.value

descriptor.value = function(){
    console.log(`传入实例方法add的参数${arguments}`)
    console.log(`实例中的age属性:${this.age}`)
    return oldAdd.apply(this, arguments)
  }

  return descriptor
}

class Math {
  @log
  add(a, b){
    return a + b
  }
}

var math = new Math()
const value = math.add(3, 6)
console.log(`value is equal to ${value}`)

结果为:

传入实例方法add的参数[object Arguments]
实例中的age属性:10
value is equal to 9

其中

descriptor.value = function(){
    console.log(`传入实例方法add的参数${arguments}`)
    console.log(`实例中的age属性:${this.age}`)
    return oldAdd.apply(this, arguments)
  }

this作用域为指向的是Math的实例math;当然this可以用target代替。

半透明的装饰模式(利用修饰类去修饰方法)

const addFly = (canFly) => {
  return (target) => {
    const extra = canFly ? '添加飞行技能' : ''
    const old_toString = target.prototype.toString

    target.prototype.toString = (...args) => {
      // 这里的target只是指Man类,不能指向实例, 应该用targey.prototype指向实例
      return old_toString.apply(target.prototype, args) + extra
    }
  }
}

@addFly(true)
class Man{
  constructor(def = 2,atk = 3,hp = 3){
    this.init(def,atk,hp)
  }
  @decorateArmour
  @decorateLight
  init(def,atk,hp){
    this.def = def // 防御值
    this.atk = atk  // 攻击力
    this.hp = hp // 血量
  }
  toString(){
    return `防御力:${this.def},攻击力:${this.atk},血量:${this.hp}`
  }
}

通过引用函数的方式改变某个函数

在不改变函数源代码的情况下,能给函数增加功能,符合开放-封闭原则

let con = () => {
 // 也可直接用function关键字来声明
  console.log('old con')
}

const _con = con

con = () => {
  _con()
  console.log('new con')
}
con()
上一篇下一篇

猜你喜欢

热点阅读