• JavaScript设计模式(三) 迭代器模式 发布-订阅模式


    迭代器模式是指提供一种方法顺序访问一个聚合对象中的各个元素,而又不需要暴露对该对象的内部表示。

    一、迭代器模式

    1.基本实现

    let each = (arr, cal) => {
      for (let i = 0; i < arr.length; i++) {
        cal.call(arr[i], i, arr[i]);
      }
    };
    each([1, 2, 3], (i, n) => {
      console.log([i, n]);
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    2.内部迭代器和外部迭代器

    (1)内部迭代器

    上面基本实现中的代码就是一种内部迭代器,函数内部已经定义好了迭代规则,全权接手整个迭代过程,外部只需要一次初始调用。
    ps.因为内部迭代器内的迭代规则已经确定,所以当迭代规则发生改变之后,迭代器函数内的代码也要对应发生改变。

    (2)外部迭代器

    外部迭代器必须显示地请求下一个元素

    以下是一个外部迭代器的基本实现:

    let Iterator = (obj) => {
      let current = 0;
      let next = () => {
        current += 1;
      }
      let isDone = () => {
        return current >= obj.length;
      }
      let getCurrItem = () => {
        return obj[current];
      }
      return {
        length: obj.length,
        next,
        isDone,
        getCurrItem,
      }
    }
    
    let compare = (iter1, iter2) => { 
      if (iter1.length !== iter2) {
        console.log('不相等');
      }
      while (!iter1.isDone() && !iter2.isDone()) {
        if (iter1.getCurrItem() !== iter2.getCurrItem()) {
          throw new Error('iter1和iter2不相等');
        }
        iter1.next();
        iter2.next();
      }
      console.log('相等');
    }
    
    let iter1 = Iterator([1, 2, 3]);
    let iter2 = Iterator([1, 2, 3]);
    compare(iter1, iter2); //相等
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36

    3.反向迭代器

    let reverseEach = (ary,cal) => {
      for (let i = ary.length - 1; i >= 0; i--) {
        cal(i, ary[i]);
      }
    }
    reverseEach([0, 1, 2], (i, n) => {
      console.log(n); // 2 1 0
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    4.中止迭代器

    迭代器可以像普通for循环中的break一样,提供一种跳出循环的方法。

    let each = (arr, cal)=> {
      for (let i = 0; i < arr.length; i++) {
        if (cal(i, arr[i]) === false) {
          break;
        }
      }
    }
    
    each([1, 2, 3, 4, 5], (i, n) => {
      if (n > 3) {
        return false;
      }
      console.log(n); //1 2 3
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    二、发布-订阅模式

    发布-订阅模式又叫观察者模式,它定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都将提前得到通知。

    1.基本实现

    let sales = {}; //创建发布者
    sales.clientList = []; //定义订阅者列表
    sales.listen = function(fn) { //添加订阅者
      this.clientList.push(fn);
    }
    sales.trigger = function() {  //发布消息
      for (let i = 0; i < this.clientList.length; i++) {
        this.clientList[i].apply(this, arguments);
      }
    }
    
    sales.listen((price, squareMeter) => {
      console.log(`price:${price},squareMeter:${squareMeter}`);
    })
    
    sales.listen((price, squareMeter) => {
      console.log(`price:${price},squareMeter:${squareMeter}`);
    })
    
    sales.trigger(2000, 800); //price:2000,squareMeter:800 price:2000,squareMeter:800
    sales.trigger(123000, 812300); //price:123000,squareMeter:812300 price:123000,squareMeter:812300
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    以上代码实现了一个基本的发布-订阅模式,但是该方式实现的是一个广播式消息发布,只要该订阅者有过订阅行为,就会收到所有发布的消息,因此将其修改为以下点对点的形式

    let sales = {}; //创建发布者
    sales.clientList = {}; //定义订阅者列表
    sales.listen = function(key,fn) { //添加订阅者
      if (!this.clientList[key]) {
        this.clientList[key] = [];
      }
      this.clientList[key].push(fn);
    }
    sales.trigger = function () {  //发布消息
      let key = Array.prototype.shift.call(arguments), fns = this.clientList[key];
      if (!fns || fns.length === 0) {
        return false;
      }
      for (let i = 0, fn; fn = fns[i++];) {
        fn.apply(this, arguments);
      }
    }
    
    sales.listen('func1',function(squareMeter) {
      console.log(`squareMeter:${squareMeter}`);
    })
    
    sales.listen('func2',function(squareMeter) {
      console.log(`squareMeter:${squareMeter}`);
    })
    
    sales.trigger('func1', 800); //squareMeter:800
    sales.trigger('func2', 812300); //squareMeter:812300
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    2.通用的发布-订阅模式实现

    let events = {
      clientList: {},
      listen: function (key, fn) {
        if (!this.clientList[key]) {
          this.clientList[key] = [];
        }
        this.clientList[key].push(fn);
      },
      trigger: function () {
        let key = Array.prototype.shift.call(arguments),
          fns = this.clientList[key];
        if (!fns || fns.length === 0) {
          return false;
        }
        for (let i = 0, fn; fn = fns[i++];) {
          fn.apply(this, arguments);
        }
      }
    };
    
    let installEvent = function(obj) {
      for (let i in events) {
        obj[i] = events[i];
      }
    }
    
    let sales = {};
    installEvent(sales);
    
    sales.listen('func1',function(squareMeter) {
      console.log(`squareMeter:${squareMeter}`);
    })
    
    sales.listen('func2',function(squareMeter) {
      console.log(`squareMeter:${squareMeter}`);
    })
    
    sales.trigger('func1', 800); //squareMeter:800
    sales.trigger('func2', 812300); //squareMeter:812300
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
  • 相关阅读:
    炫酷的宇宙空间
    【线性回归、岭回归、Lasso回归分别预测患者糖尿病病情】数据挖掘实验一
    将绿色计算进行到底,蚂蚁集团四大硬核黑科技全公开
    BricsCAD v24.1.05(CAD建模软件)
    Python实现 Leecodet
    CSS位置偏移反爬虫绕过
    华清远见(上海中心)22071
    待办事项是什么意思,怎么用?
    SpringCloud-搭建XXL-JOB任务调度平台教程
    初识设计模式 - 中介模式
  • 原文地址:https://blog.csdn.net/weixin_49971653/article/details/126172643