zoukankan      html  css  js  c++  java
  • 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);
    }
    

    设计原则验证

    • 迭代器对象和目标对象分离
    • 迭代器将使用者与目标者对象隔离开
    • 符合开放封闭原则
  • 相关阅读:
    k8s-学习笔记12-权限体系
    Linux上磁盘热插拔
    delphi hashmap
    my gcc project
    gcc dll 导出问题 GTK+Glade3 Gtk-WARNING **: Could not find signal handler 问题最终解析
    c/c++字符串定义及使用的对比
    gcc printf()打印char* str
    gcc选项-g与-rdynamic的异同
    GCC编译,库的编译使用及Makefile
    gcc test
  • 原文地址:https://www.cnblogs.com/ygjzs/p/12240147.html
Copyright © 2011-2022 走看看