灏天阁

迭代器模式

· Yin灏
/**
 * 迭代器模式
 * 在不暴露对象内部结构的同时,可以顺序地访问聚合对象内部的元素。
 */
// 迭代器
var Iterator = function (items, container) {
  // 获取父容器
  var container = (container && document.getElementById(container)) || document;
  var items = container.getElementsByTagName(items);
  var length = items.length;
  var index = 0;
  var splice = [].splice; // 缓存原生数组 splice 方法
  return {
    // 获取第一个元素
    first: function () {
      index = 0;
      return items[index]; // 获取第一个元素
    },
    // 获取最后一个元素
    second: function () {
      index = length - 1;
      return items[index]; // 获取最后一个元素
    },
    // 获取前一个元素
    pre: function () {
      if (--index > 0) {
        return items[index];
      } else {
        index = 0;
        return null;
      }
    },
    // 获取后一个元素
    next: function () {
      if (++index < length) {
        return items[index];
      } else {
        index = length - 1;
        return null;
      }
    },
    // 获取某一个元素
    get: function (num) {
      index = num >= 0 ? num % length : (num % length) + length;
      return items[index];
    },
    // 对每一个元素执行某一个方法
    dealEach: function (fn) {
      var args = splice.call(arguments, 1);
      for (var i = 0; i < args.length; i++) {
        fn.apply(items[i], args);
      }
    },
    // 对某一个元素执行某一个方法
    dealItem: function (num, fn) {
      fn.apply(this.get(num), splice.call(arguments, 2));
    },
    // 排它方式处理某一个元素
    exclusive: function (num, allFn, numFn) {
      // 对所有元素执行回调函数
      this.dealEach(allFn);
      // 如果 num 类型是数组
      if (Object.prototype.toString.call(num) === "[object Array]") {
        // 遍历数组
        for (var i = 0, len = num.length; i < len; i++) {
          this.dealItem(num[i], numFn);
        }
      } else {
        // 处理第 num 个元素
        this.dealItem(num, numFn);
      }
    },
  };
};

/**
 * 小试牛刀
 */
/*
  <ul id="container">
    <li>1</li>
    <li>2</li>
    <li>3</li>
    <li>4</li>
  </ul>
*/
var demo = new Iterator("li", "container");
console.log(demo.first()); // <li>1</li>
console.log(demo.pre()); // null
console.log(demo.next()); // <li>2</li>
console.log(demo.get(2000)); // <li>1</li>

// 处理所有元素
demo.dealEach(
  function (text, color) {
    this.innerHTML = text; // 设置内容
    this.style.background = color; // 设置背景色
  },
  "test",
  "pink"
);

// 排它思想处理第 3 个与第 4 个元素
demo.exclusive(
  [2, 3],
  function () {
    this.innerHTML = "被排除的";
    this.style.background = "green";
  },
  function () {
    this.innerHTML = "选中的";
    this.style.background = "red";
  }
);

/**
 * 数组迭代器
 */
var eachArray = function (arr, fn) {
  var i = 0,
    len = arr.length;
  for (; i < len; i++) {
    if (fn.call(arr[i], i, arr[i]) === false) {
      break;
    }
  }
};

/**
 * 对象迭代器
 */
var eachObject = function (obj, fn) {
  for (var i in obj) {
    if (fn.call(obj[i], i, obj[i]) === false) {
      break;
    }
  }
};

// 使用迭代器
for (var arr = [], i = 0; i < 5; arr[i++] = i); // 创建数组
eachArray(arr, function (i, data) {
  console.log(i, data);
});
/*
  0 1
  1 2
  2 3
  3 4
  4 5
*/

var obj = {
  a: 23,
  b: 56,
  c: 67,
};
eachObject(obj, function (i, data) {
  console.log(i, data);
});
/*
  a 23
  b 56
  c 67
*/

/**
 * 同步变量迭代器
 */

// 同步变量
var A = {
  // 所有用户共有
  common: {},
  // 客户端数据
  client: {
    user: {
      username: "雨夜清荷",
      uid: "123",
    },
  },
  // 服务端数据
  server: {},
};

// 同步变量迭代取值器
var AGetter = function (key) {
  if (!A) return undefined;
  var result = A;
  key = key.split("."); // 解析属性层析顺序
  for (var i = 0, len = key.length; i < len; i++) {
    // 如果第 i 层属性存在对应值则迭代该属性
    if (result[key[i]] !== undefined) {
      result = result[key[i]];
    } else {
      return undefined;
    }
  }
  return result;
};
console.log(AGetter("client.user.username")); // 雨夜清荷
console.log(AGetter("server.lang.local")); // undefined

/**
 * 修改或增加一些同步变量属性数据
 */
var ASetter = function (key, val) {
  if (!A) return undefined;
  var result = A;
  key = key.split(".");
  for (var i = 0, len = key.length; i < len - 1; i++) {
    if (result[key[i]] === undefined) {
      result[key[i]] = {};
    }
    if (!(result[key[i]] instanceof Object)) {
      throw new Error("A." + key.splice(0, i + 1).join(".") + " is not Object");
      return false;
    }
    result = result[key[i]];
  }
  return (result[key[i]] = val);
};
console.log(ASetter("client.module.news.sports", "on")); // on

// 当然对于一些值类型属性的数据进行子属性赋值操作是不允许的
console.log(ASetter("client.user.username.sports", "on")); // Error: A.client.user.username is not Object

- Book Lists -