amandakelake/blog

装饰者模式[设计模式]+ES7 Decorator

amandakelake opened this issue · 0 comments

参考《JS设计模式与开发实践》一书

装饰者模式

装饰者模式:在不改变对象自身的基础上,为对象动态添加行为

  • 为对象添加新功能
  • 不改变原有结构和功能

先看个最简单的例子

class Person {
  speak() {
    console.log("hello")
  }
}

class Decorater {
  constructor(target) {
    this.target = target;
  }
  // 在原有基础上添加新的行为
  speak() {
    this.target.speak();
    console.log("world")
  }
}

let p1 = new Person();
p1.speak();
console.log("————————————————");

let p2 = new Decorater(p1);
p2.speak();

7f72066d-5c2e-43a1-a9a0-0f897cf92847

ES7的Decorator

1、ES7装饰器环境

▶ npm install --save-dev babel-plugin-transform-decorators-legacy

使用babel编译

// .babelrc
{
    "plugins": ["transform-decorators-legacy"]
}

2、最简单用法

@Dec
class Demo{
  // ...
}

function Dec(target) {
  target.speak = function() {
    console.log("I can speak")
  }
}

Demo.speak(); // I can speak

3、传参数

只需要记住返回一个function

@Dec("basketball")
class Demo{
  // ...
}

function Dec(args) {
  return function(target) {
    target.speak = function() {
      console.log((`I love ${args}`))
    }
  }
}

Demo.speak(); // I love basketball

4、mixin实现

function mixins(...list) {
  return function(target) {
    Object.assign(target.prototype, ...list)
  }
}

const Foo = {
  foo() {
    console.log("I am foo")
  }
}

@mixins(Foo)
class MyClass {}

let obj = new MyClass()
obj.foo();

Foo的属性和方法混入到MyClass类,轻松实现mixins

装饰属性和方法

利用Object.defineProperty

function readonly(target, name, descriptor) {
  descriptor.writable = false, 
  return descriptor
}
function log(target, name, descriptor) {
  let oldVal = descriptor.value;
  descriptor.value = function() {
    console.log(`calling ${name} with `, arguments);
    // 执行完添加的逻辑后,再恢复原有逻辑
    // 可用于警告即将过期的属性
    return oldVal.apply(this, arguments)
  }
  return descriptor;
}

class Foo {
  @log
  speak(arg) {
    console.log('arg', arg)
  }
}

let foo = new Foo();
foo.speak('?');