Skip to content

10迭代器

迭代器是一个框架的重要设计。我们经常需要提供一种方法顺序用来处理聚合对象中各个元素,而又不暴露该对象的内部,这也是设计模式中的迭代器模式(Iterator)。

jQuery中的$.each方法就是一个典型的迭代器,通过each我们可以传入额外的function,然后来对所有的item项进行迭代操作,如下代码:

<script> $.each([52,97], function(index, value) { alert(index + ': ' + value) })

$('li').each(function(index) { console.log(index + ': ' + $(this).text()) }) </script>

针对迭代器,这里有几个特点:

☑ 访问一个聚合对象的内容而无需暴露它的内部。 ☑ 为遍历不同的集合结构提供一个统一的接口,从而支持同样的算法在不同的集合结构上进行操作。 ☑ 遍历的同时更改迭代器所在的集合结构可能会导致问题。

简单的说:封装实现,然后迭代器的聚合对象不用关心迭代的过程,从而符合SRP原则。 抛开jQuery的each方法,我们自己实现一个有简单的迭代器功能的代码:

<script> // 我们自己实现的迭代器 function each(obj, callback) { var i = 0, value, length = obj.length;

for (; i < length; i++) { callback(obj[i]); } }

var arr = ['a', 'b', 'c']; each(arr, function(name) { console.log(name); }) </script>

这样就满足了迭代模式的设计原则,对于集合内部结果常常变化各异,我们不想暴露其内部结构,但又想让客户代码透明地访问其中的元素,通过回调把逻辑给解耦出来。但是这样的处理其实太简单了,我们还要考虑至少四种情况:

☑ 聚合对象,可能是对象,字符串或者数组等类型 ☑ 支持参数传递 ☑ 支持上下文的传递 ☑ 支持循环中退出

我们简单的修改一下上面的代码:

<script> function each(obj, callback, context, arg) { var i = 0, value, length = obj.length;

for (; i < length; i++) { callback.call(context || null, obj[i], arg); } }

var arr = ['a', 'b', 'c'];

each(arr, function(name, arg) { console.log(name, arg, this); }, this, 'aaa') </script>

当然根据回调的处理,从而判断是否要立刻中断这个循环,从而节约性能,也是很简单的, 我们可以通过获取处理的返回值来处理,如下代码:

<script> function each(obj, callback, context, arg) { var i = 0, value, length = obj.length;

for (; i < length; i++) { value = callback.call(context || null, obj[i], arg);

if (value === false) {
  break;
}

} } </script>

共 20 个模块,1301 篇 Markdown 文档。