4_迭代器模式
1 简介
- 提供一种方法顺序访问一个聚合对象中的各个元素,而又不需要暴露该对象的内部表示
jQuery 中的迭代器
$.each([1, 2, 3], (i, n) => {
console.log('当前下标:' + i)
console.log('当前值:' + n)
})
2 实现自己的迭代器
/**
* @param ary 被循环的数组
* @param cb 循环中的每一步将被触发的回调函数
*/
function each(ary, cb) {
for(let i = 0, l = ary.length; i < l; i++) {
cb.call(ary[i], i, ary[i])
}
}
each([1, 2, 3], (i, n) => {
alert([i, n])
})
3 内部迭代器和外部迭代器
1. 内部迭代器
- 迭代器内部定义了迭代规则,外界无需关注其内部实现,跟迭代器的交互也仅是一次初始调用
function compare(ary1, ary2) {
if(ary1.length !== ary2.length) {
throw new Error('ary1和ary2不相等')
}
each(ary1, (i, n) => {
if(n !== ary2[i]) {
throw new Error('ary1和ary2不相等')
}
})
alert('ary1和ary2相等')
}
2. 外部迭代器
- 显式地请求迭代下一个元素,可以控制迭代的过程或顺序
function Iterator(obj) {
let current = 0
let next = () => current++
let isDone = () => current >= obj.length
let getCurrItem = () => obj[current]
return {
next,
isDone,
getCurrItem
}
}
- 改写 compare
function compare(iterator1, iterator2) {
while(!iterator1.isDone() && !iterator2.isDone()) {
if(iterator1.getCurrItem() !== iterator2.getCurrItem()) {
throw new Error('iterator1和iterator2不相等')
}
iterator1.next()
iterator2.next()
}
alert('iterator1和iterator2相等')
}
let iterator1 = Iterator([1, 2, 3])
let iterator2 = Iterator([1, 2, 3])
compare(iterator1, iterator2)
外部迭代器较内部迭代器更为复杂,但是适用面更广,也能满足更多变的需求
4 迭代类数组对象和字面量对象
for..in
function each(obj, cb) {
let value,
i = 0,
length = obj.length,
isArray = isArraylike(obj)
if(isArray) {
for(; i < length; i++) {
value = cb.call(obj[i], i, obj[i])
if(value === false) break
}
} else {
for(i in obj) {
value = cb.call(obj[i], i, obj[i])
if(value === false) break
}
}
return obj
}
5 倒序迭代器
function reverseEach(ary, cb) {
for(let l = ary.length-1; l > 0; l--) {
cb(l, ary[l])
}
}
reverseEach([0, 1, 2], (i, n) => {
console.log(n)
})
6 中止迭代器
function each(ary, cb) {
for(let i = 0, l = ary.length; i < l; i++) {
if(cb(i, ary[i]) === false) break
}
}
each([1, 2, 3, 4, 5], (i, n) => {
if(n > 3) return false
console.log(n)
})
7 应用
根据不同的浏览器获取对应的上传组件对象
1. 封装每种获取upload对象的方法
// IE上传控件
function getActiveUploadObj() {
try {
return new ActiveXObject('TXFTNActiveX.FTNUpload')
} catch(e) {
return false
}
}
function getFlashUploadObj() {
if(supportFlash()) {
var str = `
<object type="application/x-shockwave-flash"></object>
`
return $(str).appendTo($('body'))
}
return false
}
// 表单上传
function getFormUploadObj() {
var str = `
<input name="file" type="file" class="ui-file" />
`
return $(str).appendTo($('body'))
}
2. 迭代器
- 提供一个可以被迭代的方法,使得函数依照优先级被循环迭代
- 如果正在被迭代的函数返回一个对象,则表示找到了正确的 upload 对象,反之如果该函数返回 false,则让迭代器继续工作
function iteratorUploadObj() {
for(let fn in arguments) {
let uploadObj = fn()
if(uploadObj !== false) {
return uploadObj
}
}
}
let uploadObj = iteratorUploadObj(
[
getActiveUploadObj,
getFlashUploadObj,
getFormUploadObj
]
)