JavaScript迭代器模式

JavaScript迭代器模式

  • 1 什么是迭代器模式
  • 2 实现一个迭代器
  • 3 内部迭代器和外部迭代器
    • 3.1 内部迭代器
    • 3.2 外部迭代器
  • 4 迭代类数组对象和字面量对象

1 什么是迭代器模式

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

迭代器模式可以把迭代的过程从业务逻辑中分离出来,在使用迭代器模式之后,即使不关心对象的内部构造,也可以按顺序访问其中的每个元素。

JavaScript有内置的迭代器Array.prototype.forEach

2 实现一个迭代器

下面来实现一个迭代器函数eacheach函数接受2个参数,第一个为一个数组,第二个为每一次循环后要触发的回调函数,代码如下:

function each(arr, callback) {
  // 对arr循环遍历,每一次遍历调用callback
  for (let i = 0, l = arr.length; i < l; i++) {
    callback.call(arr[i], i, arr[i]);
  }
}

3 内部迭代器和外部迭代器

3.1 内部迭代器

刚才编写的each函数属于内部迭代器,因为在each函数内部已经定义好了迭代的规则,外部只需要调用一次就可以。

内部迭代器不关心具体的实现,因此调用时非常方便,但是这也刚好是内部迭代器的缺点,因为内部迭代器的迭代规则已经被提前规定好了,如果我们想同时迭代2个数组,上面的each函数是无法实现的。

比如,判断2个数组里元素的值是否完全相等,不能改动each函数,代码如下:

function compare(arr1, arr2) {
  // 如果两个数组长度不相同,不可能相等
  if (arr1.length !== arr2.length) {
    console.log("arr1和arr2不相等");
    return;
  }
  each(arr1, function (i, n) {
    // i为arr1每一项索引,n为arr1每项的值
    if (n !== arr2[i]) {
      console.log("arr1和arr2不相等");
      return;
    }
    console.log("arr1和arr2相等");
  });
}

3.2 外部迭代器

外部迭代器必须显式地请求迭代下一个元素,它增加了一些调用的复杂度,但相对也增强了迭代器的灵活性,我们可以手工控制迭代的过程或者顺序。

实现一个外部迭代器:

function Iterator(obj) {
  var current = 0; // 记录当前的索引

  // 下一个位置的索引
  var next = function () {
    current += 1;
  };

  // 是否已经迭代完成
  var isDone = function () {
    return current >= obj.length;
  };

  // 获取当前位置的数据
  var getCurrentItem = function () {
    return obj[current];
  };

  return {
    next,
    isDone,
    getCurrentItem,
  };
}

根据以上外部迭代器,我们可以这样改写compare函数:

function compare(iterator1, iterator2) {
  while (!iterator1.isDone() && !iterator2.isDone()) {
    if (iterator1.getCurrentItem() !== iterator2.getCurrentItem()) {
      console.log("arr1和arr2不相等");
      return;
    }
    iterator1.next();
    iterator2.next();
  }
  console.log("arr1和arr2相等");
}

var iterator1 = Iterator([1, 2, 3]);
var iterator2 = Iterator([2, 3, 4]);

compare(iterator1, iterator2); // arr1和arr2不相等

外部迭代器虽然调用方式相对复杂,但它的适用面更广,也能满足更多变的需求。

4 迭代类数组对象和字面量对象

迭代器模式不仅可以迭代数组,还可以迭代一些类数组的对象,比如arguments{ 0: "a", 1: "b" }等。无论是内部迭代器还是外部迭代器,只要被迭代的聚合对象拥有length属性而且可以用下标访问,那它就可以被迭代。

JavaScript中,for in语句可以用来迭代普通字面量对象的属性。jQuery中提供了$.each函数来封装各种迭代行为:

$.each = function (obj, callback) {
  var value,
    i = 0,
    length = obj.length,
    isArray = isArraylike(obj);
  if (isArray) {
    // 迭代类数组
    for (; i < length; i++) {
      value = callback.call(obj[i], i, obj[i]);
      if (value === false) {
        break;
      }
    }
  } else {
    for (i in obj) {
      // 迭代 object 对象
      value = callback.call(obj[i], i, obj[i]);
      if (value === false) {
        break;
      }
    }
  }
  return obj;
};

你可能感兴趣的:(JavaScript,javascript,迭代器模式,开发语言)