迭代器模式

定义:提供一种方法顺序访问一个聚合对象中的各个元素,而又不暴露该对象的内部表示。
应用:jQuery 中的\$.each 函数、forEach 内置迭代器、根据不同情况执行不同的函数
分类:

  1. 内部迭代器
    定义迭代规则,完全接手整个迭代过程,外部只需要一次初试调用,不需要关心迭代器内部实现,上面的 each 函数就属于内部迭代器。
  2. 外部迭代器
    必须显式地请求迭代下一个元素,增加了调用复杂度,但是增强了迭代器的灵活性,可以手工控制迭代的过程或者顺序。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
const Iterator = obj => {
let current = 0; //当前下标
// 继续迭代
const next = () => {
current += 1;
};
// 是否迭代完成
const isDone = () => {
return current >= obj.length;
};
// 获取当前的元素
const getCurrItem = () => {
return obj[current];
};
return {
next,
isDone,
getCurrItem,
length: obj.length
};
};
// 实现判断两个数组是否完全相等
const compare = (iterator1, iterator2) => {
if (iterator1.length !== iterator2.length) {
return false;
}
while (!iterator1.isDone() && !iterator2.isDone()) {
if (iterator1.getCurrItem() !== iterator2.getCurrItem()) {
return false;
}
iterator1.next();
iterator2.next();
}
return true;
};

const iterator1 = Iterator([1, 2, 3]);
const iterator2 = Iterator([1, 2, 3]);
compare(iterator1, iterator2); // true

实现:

实现自己的迭代器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
const each = (array, callback) => {
for (let i = 0, l = array.length; i < l; i++) {
//下标和元素传给callback函数
// 如果回调函数执行结果为false,提前终止循环
if (callback(i, array[i]) === false) {
break;
}
}
};
each([1, 2, 3], (i, n) => {
if (n === 2) {
// 终止循环
return false;
}
console.log(i, n);
});

根据不同的浏览器获取相应的上传组件对象

实现思路:普通方法使用 try-catch 和 if-else 实现,但是如果增加了别的上传方式,就要改变原函数的条件分支。改造成,每种获取 upload 对象的方法都封装在各自的函数中,使用迭代器获取 upload 对象,直到获取到一个可用的为止。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
// 每一个方法都表示如果找到了正确的upload对象,就返回该对象,否则返回false,让迭代器继续工作
const getActiveUploadObj = () => {
try {
return new ActiveXObject('TXFTNActiveX.FTNUpload');
} catch (e) {
return false;
}
};

const getFlashUploadObj = () => {
if (supportFlash()) {
const str = '<object type="application/x-shockwave-flash"></object>';
return $(str).appendTo($('body'));
}
return false;
};

const getFormUpladObj = () => {
const str = '<input name="file" type="file" class="ui-file"/>'; // 表单上传
return $(str).appendTo($('body'));
};

const iteratorUploadObj = () => {
for (let i = 0, fn; (fn = arguments[i++]); ) {
const uploadObj = fn();
if (uploadObj !== false) {
return uploadObj;
}
}
};

const uploadObj = iteratorUploadObj(getActiveUploadObj, getFlashUploadObj, getFormUpladObj);

aaaa啊啊啊