设计模式之迭代器模式

一、基础介绍

在不暴露对象内部结构的同时,可以顺序地访问聚合对象内部的元素。

二、分类介绍

2.1 数组迭代器
var eachArray = function (arr, fn) {
  if (Object.prototype.toString.call(arr) !== '[object Array]') throw new Error("不是数组");
  var i = 0,
      len = arr.length;
  for(; i < len; i++) {
    if (fn.call(arr[i], i, arr[i]) === false) {
      break;
    }
  }
}
2.2 对象迭代器
var eachObject = function(obj, fn) {
  if (Object.prototype.toString.call(arr) !== '[object Object]') throw new Error("不是对象");
  for(var i in obj) {
    if (fn.call(obj[i], i, obj[i]) === false) {
      break;
    }
  }
}
2.3 内部迭代器

迭代器内部已经定义好了迭代规则。

举例: 上面提到的数组和对象迭代器就是内部迭代器。

2.4 外部迭代器

外部迭代器必须显示地请求迭代下一个元素。

举例:Generator 生成的迭代器

var createIterator = function (items) {
  var current = 0;
  return {
    next() {
      var done = current  >= items.length;
      var value = !done ? items[current] : undefined;

      current++;

      return {
        done,
        value
      }
    }
  }
}
2.5 倒序迭代器

即改变遍历的顺序为倒序。

2.6 中止迭代器

迭代器内部提供跳出循环的方法。例如上方数组迭代器中的:

if (fn.call(arr[i], i, arr[i]) === false) {
  break;
}

表示当回调函数的返回值为 false ,则提前终止循环。

2.7 同步变量迭代器

通俗的讲就是采用迭代器自动处理,对于获取嵌套属性的判断。

比如下面的数据结构,直接获取 A.info.id 可能会报错。一般都是 A && A.info && A.info.id ,但是这样的判断导致代码冗余。

同步变量

var A = {
  str: 'lee',
  arr: [],
  obj: {
    id: 123
  }
}

getter

// root 表示外层变量
// key 表示内部链式调用
function getter(root, key) {
  if (!root) return undefined;
  var keys = key.split('.');
  let result = root;
  
  for( var i = 0, len = keys.length; i < len; i++) {
    if (result[keys[i]] !== undefined) {
      result = result[keys[i]];
    } else {
      return undefined;
    }
  }
  return result;
}
调用示例

setter

function setter(root, key, val) {
  if (!root) return false;
  let result = root;
  let keys = key.split('.');

  for( var i = 0, len = keys.length; i < len - 1; i++) {
    // 如果第 i 层属性对应的值不存在,则定义成对象
    if (result[keys[i]] === undefined) {
      result[keys[i]] = {};
    }

    // 如果第 i 层属性对应的值不是对象的一个实例,则抛出错误
    if (!(result[keys[i]] instanceof Object)) {
      throw new Error('root.' + keys.splice(0, i + 1).join(',') + 'is not object');
      return false;
    }
    
    result = result[keys[i]];
  }
  // 返回设置成功的属性值,注意此时 i 代表的是 len - 1
  return result[keys[i]] = val;
}
  • 给已经存在的 obj 属性添加新的属性 name


    设计模式之迭代器模式_第1张图片
    示例 1
  • 给不存在的属性 serve 添加属性 name,这里 serve 被初始化成对象了


    设计模式之迭代器模式_第2张图片
    示例 2
  • 给非对象的属性 str 添加属性 name,很明显 str 是基本类型,不能继续添加属性


    示例 3
2.8 排他方式处理

比如有 5 个元素,除了第 3 个元素之外,都要执行赋值为 0 的操作。

// 处理某个元素
dealItem() {
  // do things
}
// 排除
except(arr, n) {
  for (let i = 0; i < arr.length; i++) {
    if (i !== n) {
      dealItem();
    }
  }
}

这种方式比手工调用多次 dealItem() 好很多。

2.9 应用迭代器消除条件语句分支
  • 结合策略模式
    如果条件已知,不同条件对应的处理方式之间没有关系,互相独立,适合采用策略模式。

  • 结合中止迭代器
    如果条件语句需要动态计算,存在优先级,或者存在关系,适合采用中止迭代器。

    举例:浏览器嗅探

参考

《JavaScript 设计模式与开发实践》曾探
《JavaScript 设计模式》张容铭
Javascript设计模式系统讲解与应用

你可能感兴趣的:(设计模式之迭代器模式)