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
  ]
)
posted on 2023-05-09 10:49  pleaseAnswer  阅读(21)  评论(0编辑  收藏  举报