javascript设计模式之实战案例

714 阅读4分钟

PubSub ——“发布/订阅”模式

Vue中provide和inject

  • 作用:用于父组件向子孙组件传递数据
  • 原理向上找寻
  • 何时使用 provide是非响应的,那么就决定它注定不能用于组件通信,和vuex根本没有可比性。至于为什么引入inject,可以参考mixin,简单来说就是业务逻辑的抽象,hook的抽象实现固然很好,但是没有必要把难以复用的逻辑抽象成函数,如果只是简单提供给子组件使用,那就使用provide,inject,否则使用hook,vuex不考虑,没人用vuex抽象业务逻辑。

EventBus(this.emit,this.on)

Vue之EventBus实现

  • 作用:用于兄弟组件传递数据
  • 原理发布/订阅方法,通常称为 Pub/Sub
EventBus.$emit("incremented", { num:this.num, deg:this.deg }); //发布
EventBus.$on("decreased", ({num,deg}) => {} //接受
EventBus.$off('decreased', {})  //移除

PubSub ——“发布/订阅”模式

  • 作用
  1. 支持简单的广播通信,当对象状态发生改变时,会自动通知已经订阅过的对象。
  2. 可以应用在异步编程中 替代回调函数 可以订阅ajax之后的事件 只需要订阅自己需要的部分 (那么ajax掉用发布之后订阅的就可以拿到消息了)(不需要关心对象在异步运行时候的状态)
  3. 对象之间的松耦合 两个对象之间都互相不了解彼此 但是 不影响通信 当有新的订阅者出现的时候 发布的代码无需要改变 同样发布的代码改变 只要之前约定的事件的名称没有改变 也不影响订阅
  • 缺点
  1. 创建订阅者需要消耗一定的时间和内存。
  2. 虽然可以弱化对象之间的联系,如果过度使用的话,反而使代码不好理解及代码不好维护等等
var Event = (function () {
      var list = {},
        listen,
        trigger,
        remove;
      listen = function (key, fn) {
        if (!list[key]) {
          list[key] = [];
        }
        list[key].push(fn);
      };
      trigger = function () {
        var key = Array.prototype.shift.call(arguments),
          fns = list[key];
        if (!fns || fns.length === 0) {
          return false;
        }
        for (var i = 0, fn; fn = fns[i++];) {
          fn.apply(this, arguments);
        }
      };
      remove = function (key, fn) {
        var fns = list[key];
        if (!fns) {
          return false;
        }
        if (!fn) {
          fns && (fns.length = 0);
        } else {
          for (var i = fns.length - 1; i >= 0; i--) {
            var _fn = fns[i];
            if (_fn === fn) {
              fns.splice(i, 1);
            }
          }
        }
      };
      return {
        listen: listen,
        trigger: trigger,
        remove: remove
      }
    })();
    Event.listen("color", function (size) {
      console.log(size)
    })
    Event.trigger("color", 42);

单例模式

class类

  • 是什么 es6提供的一种新的生成实例对象的方法class可以看作只是一个语法糖 es5 构造函数的另外一种写法

  • 作用 更接近传统语言的写法新的class写法只是让对象原型的写法更加清晰、更像面向对象编程的语法

  • es5以前生成对象

function Person(name, sex) {
    this.name = name;
    this.sex = sex
}
Person.prototype.say = function () {
  console.log('学前端很幸福')
};
let person1 = new Person('张三','男')
console.log(person1.name);
person1.say()
  • es6实现
class Person {
    constructor(name,sex){
        this.name = name
        this.sex = sex
    }
    say(){
        console.log('学前端很幸福');
    }
}
let person1 = new Person('张三','男')

console.log(person1.name); // 张三
person1.say() // 我会说话

  • constructor 方法  constructor方法是类的默认方法,通过new命令生成对象实例时,自动调用该方法。一个类必须有constructor方法,如果没有显式定义,一个空的constructor方法会被默认添加。

  • 静态属性 静态属性指的是 Class 本身的属性,即Class.propName,而不是定义在实例对象(this)上的属性。

class Person {
    static age = 18
    name = '张三'
}
let person = new Person();
console.log(person.age); // undefined

  • 静态方法 类相当于实例的原型,所有在类中定义的方法,都会被实例继承。如果在一个方法前,加上static关键字,就表示该方法不会被实例继承,而是直接通过类来调用,这就称为“静态方法”。
class Foo {
  static classMethod() {
    return 'hello';
  }}

Foo.classMethod() // 'hello'
foo.classMethod()

  1. ES6中的单例模式
  • ES6创建对象 ES6中创建对象时引入了class和constructor用来创建对象。下面我们来使用ES6的语法实例化苹果公司
class LingYuan {
  constructor(name, creator, products) {
    this.name = name;
    this.creator = creator;
    this.products = products;
  }
}

let lyCompany = new LingYuan('零远教育', '裴广斌', ['es6', 'vue', 'react', 'node']);
let lyCopyCompany = new LingYuan('苹果公司', 'walker', ['es7', 'vue', 'react', 'node']);
  • ES6中创建单例模式 零远公司明显有且只有一个, 就是裴老师创建的那个, 哪能容别人进行复制?所以LingYuan应该是一个单例, 现在我们使用ES6的语法将constructor改写为单例模式的构造器。

  • ES6的静态方法优化代码

ES6中提供了为class提供了static关键字定义静态方法, 我们可以将constructor中判断是否实例化的逻辑放入一个静态方法getInstance中,调用该静态方法获取实例, constructor中只包需含实例化所需的代码,这样能增强代码的可读性、结构更加优化。

    class SingletonLy {
      constructor(name, creator, products) {
        this.name = name;
        this.creator = creator;
        this.products = products;
      }
      //静态方法
      static getInstance(name, creator, products) {
        if (!this.instance) {
          this.instance = new SingletonLy(name, creator, products);
        }
        return this.instance;
      }
    }
    let lyCompany = SingletonLy.getInstance('零远思维', '裴广斌', ['vue', 'react', 'node', 'js']);
    let lyCopyCompany = SingletonLy.getInstance('零远copy', 'walker', ['vue', 'react', 'node', 'js'])
    console.log(lyCompany === lyCopyCompany);