《js 设计模式与开发实践》读书笔记 7
迭代器模式是指提供一种方法顺序访问一个聚合对象中的各个元素,而又不需要暴露该对象的内部表示。迭代器模式可以把迭代的过程从业务逻辑中分离出来,在使用迭代器模式之后,即使不关心对象的内部构造,也可以按顺序访问其中的每个元素。
我们来实现一个 each 函数,each 函数接受两个参数,第一个为被循环的数组,第二个为循环中每一步后将被触发的回调函数。
var each = function (ary, callback) {
for (let i = 0; i < ary.length; i++) {
const element = ary[i]
callback(element, i)
}
}
each([1, 2, 3], function (i, n) {
console.log(i, n)
})
迭代器可以分为内部迭代器和外部迭代器,它们又各自的使用场景。上面的 each 函数是内部迭代器,each 函数的内部已经定义好了迭代规则,它完全接手整个迭代过程,外部只需要一次初始调用。内部迭代器在调用的时候非常方便,外界不用关心迭代器内部的实现,跟迭代器的交互仅仅是一次初始调用,但也这也是内部迭代器的缺点。因为内部迭代器的迭代规则已经被提前规定,就无法满足一些别的请求。
假如现在有个需求,需要判断 2 个数组里元素的值是否完全相等,如果不改写 each 函数本身的代码,我们只能在回调函数修改了。
var each = function (ary, callback) {
for (let i = 0; i < ary.length; i++) {
const element = ary[i]
callback(element, i)
}
}
var compare = function (ary1, ary2) {
if (ary1.length != ary2.length) {
console.log('ary不相等。')
return
}
each(ary1, function (i, n) {
if (i != ary2[n]) {
console.log('ary不等')
return
}
})
console.log('ary相等')
}
compare([1, 2, 3, 4], [1, 2, 2, 3])
这个函数不好看,但是目前的需求暂时可以完成。外部迭代器必须显式请求迭代下一个元素。
var Iterator = function (obj) {
var current = 0
var next = function () {
current += 1
}
var isDone = function () {
return current >= obj.length
}
var getCurrentItem = function () {
return obj[current]
}
return {
next: next,
isDone: isDone,
getCurrentItem: getCurrentItem,
length: obj.length
}
}
外部迭代器调用方式相对复杂,但是更容易满足多变的需求。迭代器模式不仅可以迭代数组,还可以迭代一些类数组的对象。只要迭代的聚合对象拥有 length 属性而且可以用下标访问,那它就可以迭代。
上面的 foreach 函数我们想要便利到对应方法停止就需要把条件传进去,然后 break 了,这也是为什么 foreach 函数会直到数组玄幻完毕。而要用 every 函数了。every 写一个。
var every = function (ary, callback) {
for (let i = 0; i < ary.length; i++) {
const element = ary[i]
if (!callback(element, i)) {
break
}
}
}
var compare = function (ary1, ary2) {
if (ary1.length != ary2.length) {
console.log('ary不相等。')
return false
}
every(ary1, function (i, n) {
if (i != ary2[n]) {
console.log('ary不等')
return false
}
return true
})
console.log('ary相等')
}
compare([1, 2, 3, 4], [1, 2, 2, 3])
迭代器是一种相对简单的模式,简单到很多时候我们都不认为它是一种设计模式。