JavaScript-迭代器模式

迭代器模式

顺序访问一个集合
使用者无需知道集合内部结构(封装)

jQuery 示例

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <title>Document</title>
  </head>
  <body>
    <p>jquery each</p>
    <p>jquery each</p>
    <p>jquery each</p>

    <script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js"></script>
    <script>
      var arr = [1, 2, 3];
      var nodeList = document.getElementsByTagName("p");
      var $p = $("p");

      // 要对这三个变量进行遍历,需要写三个遍历方法
      // 第一
      arr.forEach(function(item) {
        console.log(item);
      });
      // 第二
      var i,
        length = nodeList.length;
      for (i = 0; i < length; i++) {
        console.log(nodeList[i]);
      }
      // 第三
      $p.each(function(key, p) {
        console.log(key, p);
      });

      // 如何能写出一个方法来遍历这三个对象呢
      function each(data) {
        var $data = $(data);
        $data.each(function(key, p) {
          console.log(key, p);
        });
      }
      each(arr);
      each(nodeList);
      each($p);
    </script>
  </body>
</html>

传统 UML 类图

javascript 中的 UML 类图

class Iterator {
  constructor(conatiner) {
    this.list = conatiner.list;
    this.index = 0;
  }
  next() {
    if (this.hasNext()) {
      return this.list[this.index++];
    }
    return null;
  }
  hasNext() {
    if (this.index >= this.list.length) {
      return false;
    }
    return true;
  }
}

class Container {
  constructor(list) {
    this.list = list;
  }
  getIterator() {
    return new Iterator(this);
  }
}

// 测试代码
let container = new Container([1, 2, 3, 4, 5]);
let iterator = container.getIterator();
while (iterator.hasNext()) {
  console.log(iterator.next());
}

使用场景

jQuery each

上面的 jQuery 代码就是

ES6 Iterator

ES6 Iterator 为何存在?

  • es6 语法中,有序集合的数据类型已经有很多了
  • Array Map Set String TypedArray argument Nodelist
  • 需要有一个统一的遍历接口来遍历所有的数据类型
  • (注意,object 不是有序集合,可以用 Map 代替)

es6 Interator 是什么?

  • 以上数据类型,都有[Symbol.iterator]属性
  • 属性值是函数,执行函数返回一个迭代器
  • 这个迭代器就有 next 方法可以顺序迭代子元素
  • 可运行 Array.prototype[Symbol.iterator]来测试

示例

let arr = [1, 2, 3, 4]
let nodeList = document.getElementsByTagName('p')
let m = new Map()
m.set('a', 100)
m.set('b', 200)

function each(data) {
    // 生成遍历器
    let iterator = data[Symbol.iterator]()

    console.log(iterator.next())  // 有数据时返回 {value: 1, done: false}
    console.log(iterator.next())
    console.log(iterator.next())
    console.log(iterator.next())
    console.log(iterator.next())  // 没有数据时返回 {value: undefined, done: true}

each(arr)
each(nodeList)
each(m)

上面代码改进

let arr = [1, 2, 3, 4];
let nodeList = document.getElementsByTagName("p");
let m = new Map();
m.set("a", 100);
m.set("b", 200);

function each(data) {
  // 生成遍历器
  let iterator = data[Symbol.iterator]();

  let item = { done: false };
  while (!item.done) {
    item = iterator.next();
    if (!item.done) {
      console.log(item.value);
    }
  }
}

each(arr);
each(nodeList);
each(m);

es6 很聪明提供了for of

let arr = [1, 2, 3, 4];
let nodeList = document.getElementsByTagName("p");
let m = new Map();
m.set("a", 100);
m.set("b", 200);

function each(data) {
  for (let item of data) {
    console.log(item);
  }
}

each(arr);
each(nodeList);
each(m);

ES6 Interator 与 Generator

  • Interator 的价值不限于上述几个类型的遍历
  • 还有 Generator 函数的使用
  • 即只要返回的数据符合 Interator 接口的要求
function* helloWorldGenerator() {
  yield "hello";
  yield "world";
  return "ending";
}

var hw = helloWorldGenerator();
console.log(hw.next());
console.log(hw.next());
console.log(hw.next());
console.log(hw.next());

//输出
// { value: 'hello', done: false }
// { value: 'world', done: false }
// { value: 'ending', done: true }
// { value: undefined, done: true }
function* foo() {
  yield 1;
  yield 2;
  yield 3;
  yield 4;
  yield 5;
  return 6;
}

for (let v of foo()) {
  console.log(v);
}

设计原则验证

  • 迭代器对象和目标对象分离
  • 迭代器将使用者与目标者对象隔离开
  • 符合开放封闭原则
(0)

相关推荐

  • es6新增新特性简要总结

    es6简介 es6是在2015年6月正式颁布的新标准,es6基本上实现了所有ECMAScript 规范,以后每年的6月都会发布新版本,但改动不大. let 变量 使用let 关键字来申明的变量拥有以下 ...

  • 摸鱼日记之—— js 中的遍历器:Iterator 与 for of

    摸鱼日记之—— js 中的遍历器:Iterator 与 for of

  • PHP设计模式之迭代器模式

    PHP设计模式之迭代器模式 一说到这个模式,就不得不提循环语句.在<大话设计模式>中,作者说道这个模式现在的学习意义更大于实际意义,这是为什么呢?当然就是被foreach这货给整得.任何语 ...

  • [PHP小课堂]PHP设计模式之迭代器模式

    [PHP小课堂]PHP设计模式之迭代器模式 关注公众号:[硬核项目经理]获取最新文章 添加微信/QQ好友:[DarkMatterZyCoder/149844827]免费得PHP.项目管理学习资料

  • PHP设计模式—迭代器模式

    定义: 迭代器模式(Iterator):提供一种方法顺序访问一个聚合对象中各个元素,而又不暴露该对象的内部表示. 结构: Iterator:迭代器接口,用于定义得到开始对象.得到下一个对象.判断是否到 ...

  • 软件设计模式修炼 -- 迭代器模式

    迭代器模式是一种使用频率非常高的设计模式,迭代器用于对一个聚合对象进行遍历.通过引入迭代器可以将数据的遍历功能从聚合对象中分离出来,聚合对象只负责存储数据,聚合对象只负责存储数据,而遍历数据由迭代器来 ...

  • 大话设计模式笔记(十七)の迭代器模式

    迭代器模式 定义 提供一种方法顺序访问一个聚合对象中各个元素,而又不暴露该对象的内部表示. 什么时候用? 当你需要访问一个聚集对象,而且不管这些对象是什么都需要遍历的时候,你就应该考虑用迭代器模式. ...

  • 简说设计模式——迭代器模式

    一.什么是迭代器模式 迭代器这个词在Java中出现过,即Java中使用Iterator迭代器对集合进行遍历,但迭代器模式算是一个没落的模式,基本上没人会单独写一个迭代器,除非是产品性质的开发. 迭代器 ...

  • 结合JDK源码看设计模式——迭代器模式

    前言: Iterator翻译过来就是迭代器的意思.在前面的工厂模式中就介绍过了iterator,不过当时介绍的是方法,现在从Iterator接口的设计来看,似乎又是一种设计模式,下面我们就来讲讲迭代器 ...

  • [javascript] cdn模式下vue和vue-router实现路由

    案例大部分都是用npm模式的,现在这个是使用cdn模式的更符合后端开发 html部分 , 注意template标签 ,定义上的id <script src="https://cdn.j ...

  • javascript工厂模式,调用的方法

    function obj(){ var o={}; o.name="jim"; o.age=29; o.func=function(){ console.log(this.name ...

  • 设计模式之迭代器与组合模式(三)

    现在我们已经能愉快地看着一页一页罗列出来的菜单进行点菜了.现在又有的小伙伴希望能够加上一份餐后甜点的"子菜单".怎么办呢?我们不仅仅要支持多个菜单,甚至还要支持菜单中的菜单. 如果 ...