什么是迭代器模式?

迭代器模式是指提供顺序访问一个集合对象中的各个元素,而又不需要暴露该对象的内部表示。迭代器模式可以把迭代过程从业务逻辑中分离出来,使用迭代器模式之后,即使不关心内部构造,也可以按某种顺序访问。

以遍历数组每个数值,并对打印每个数为例子。

const arr = [1, 2, 3, 4, 5];
// 传统方法, 我们实现顺序遍历
for (let i = 0; i < arr.length; ++ i) {
  console.log(arr[i], i);
}

// 使用迭代器模式的方法
arr.forEach(function(val, index, arr) {
  console.log(val, index);
});

上面代码我们能够非常容易的看出区别,传统方法,需要我们关注遍历数组的方式和业务处理,而使用 迭代器模式 的方式,让我们只需要关注业务处理。迭代器模式 将对象内部遍历方式隐藏起来了。通过统一暴露遍历接口,我们就能实现对象遍历。

迭代器模式在 JS 中的应用

ES6 以后 JS 引入了 迭代协议。迭代协议分为两部分 可迭代协议迭代器协议

可迭代协议:对象如果实现了 Symbol.iterator 方法,那么这个对象就被称为 可迭代对象。而这个方法定义了迭代这个对象的规则。

迭代器协议:规定 Symbol.iterator 方法的返回值,统一迭代接口。

  • [Symbol.iterator]: function() {
      
      return {
        next() {
        	return {
        		done: false, // 表示该对象还未遍历完成
        		value: x, // 当前遍历对象的值
      		};
      	},
        return(value) { // 可选
          // 迭代时候,break 执行该方法
          return {
            done: true,
            value: undefined
          }
        },
        throw(exception) { // 可选
          // 迭代过程中出现错误。
        }
      }
    }
    

知道规范后我们来做一个实际的例子。例如:我们有一个班级对象,里面存有学生信息。当我们迭代这个对象时,能够获取每个学生信息。

const classroom = {
  classmates: [{name: "acwink", age: 18}, {name: "lihua", age: 20}, {name: "zhange", age: 19}],
  [Symbol.iterator]() {
    let idx = 0;
    const classmates = this.classmates;
    const len = classmates.length;
    
    return {
      next() {
        return {
          done: idx >= len,
          value: classmates[idx ++]
        }
      },
      return() {  // continue break throw new Error() 触发
        console.log("break 打断结束");
        return {
          done: true,
          value: undefined
        }
      },
      throw(exception) {  // 主要配合生成器函数使用
        console.log("throw 打断结束, ", exception.message);
        return {
          done: true
        }
      }
    }
  }
};

/**
 * { name: 'acwink', age: 18 }
 * { name: 'lihua', age: 20 }
 * { name: 'zhange', age: 19 }
 */
for (const classmate of classroom) {
  console.log(classmate);
}

/**
 * { name: 'acwink', age: 18 }
 * break 打断结束
 */
for (const classmate of classroom) {
  console.log(classmate);
  break; // throw new Error() or continue
}
console.log("===========")

 

这这段代码中,我们为classroom对象内部定义的遍历规则,外部只需要遍历它即可,而无需关心怎么遍历的。