Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
amandakelake opened this issue Jan 22, 2019 · 0 comments
Open

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

amandakelake opened this issue Jan 22, 2019 · 0 comments

Comments

@amandakelake
Copy link
Owner

参考《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('?');
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant