JavaScript-迭代器模式

迭代器模式

順序訪問一個集合
使用者無需知道集合內部結構(封裝)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 代碼就是css

ES6 Iterator

ES6 Iterator 爲什麼存在?html

  • es6 語法中,有序集合的數據類型已經有不少了
  • Array Map Set String TypedArray argument Nodelist
  • 須要有一個統一的遍歷接口來遍歷全部的數據類型
  • (注意,object 不是有序集合,能夠用 Map 代替)

es6 Interator 是什麼?java

  • 以上數據類型,都有[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)

上面代碼改進node

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 ofjquery

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);
}

設計原則驗證

  • 迭代器對象和目標對象分離
  • 迭代器將使用者與目標者對象隔離開
  • 符合開放封閉原則
相關文章
相關標籤/搜索