迭代器模式是指提供一种方法顺序访问一个聚合对象中的各个元素,而又不需要暴露该对象的内部表示。
迭代器模式可以把迭代的过程从业务逻辑中分离出来,在使用迭代器模式之后,即使不关心对象的内部构造,也可以按顺序访问其中的每个元素
许多浏览器都支持 Javascript 的 Array.prototype.forEach
迭代器可以分为 内部迭代器 和 外部迭代器
一、jQuery 中的迭代器
1 $.each( [1,2,3,4], function (i, n) {
2 console.log( "当前下表为:" + i + " , 当前值为:" + n );
3 });
二、自实现一个迭代器
1 // 自己实现一个数组迭代器
2 var each = function( arry, callback ){
3 for( var i = 0, l = arry.length; i < l; i++){
4 callback.call( arry[i], i, arry[ i ]);
5 }
6 };
7 each([1,2,3,4], function (i, n) {
8 console.log( i + " - " + n ); // 输出数组下标和值
9 });
三、内部迭代器
上边的 each 函数属于内部迭代器, each 函数内部已经定义好了迭代原则,它完全接手整个迭代过程,外部只需要一次初始调用。
内部迭代器的优点也刚好是它的缺点 - 使用方便,迭代交互也仅仅是一次初始调用
示例: 在不改写 each 本身的代码前提,实现判断两个数组里元素的值是否完全相等
1 //判断两个数组的值是否完全相等
2 var compare = function( arry1, arry2){
3 if( arry1.length !== arry2.length ){
4 throw new Error( "arry1和arry2不相等" );
5 }
6 each( arry1, function( i, n ){
7 if( n !== arry2[i] ){
8 throw new Error("arry1和arry2不相等");
9 }
10 });
11 console.log( "arry1和arry2相等" );
12 };
13
14 compare( [1,2,3,4], [1,2,3]);
四、外部迭代器
外部迭代器必须显式地请求迭代下一个元素
外部迭代器增加了一些调用的复杂度,但相对的也增强了迭代器的灵活性,我们可以手工控制迭代的过程或者顺序
示例: 重写 compare
外部迭代器:
1 // 外部迭代器
2 var Iterator = function (obj) {
3 var current = 0;
4
5 var next = function(){
6 current += 1;
7 };
8
9 var isDone = function(){
10 return current >= obj.length;
11 };
12
13 var getCurrItem = function(){
14 return obj[ current ];
15 };
16
17 return {
18 next: next,
19 isDone: isDone,
20 getCurrItem: getCurrItem
21 }
22 }
View Code
改写 Compare
1 // 改写 Compare
2 var compare = function( iterator1, iterator2 ){
3 while( iterator1.isDone() && iterator2.isDone() ){
4 if( iterator1.getCurrItem() !== iterator2.getCurrItem() ){
5 throw new Error( "iterator1 和 iterator2不相等" );
6 }
7 iterator1.next();
8 iterator2.next();
9 }
10 console.log( "iterator1 和 iterator2相等" );
11 };
12
13 var iterator1 = Iterator( [1,2,3,4] );
14 var iterator2 = Iterator( [1,2,3,4] );
15
16 compare(iterator1,iterator2);
View Code
五、中止迭代器
重写 each 函数实现中止迭代
1 // 重写 each 函数实现中止迭代
2 var each = function( arry, callback ){
3 for( var i = 0, l = arry.length; i < l; i++ ){
4 // callback 的执行结果返回false,提前中止迭代
5 if( callback( i, arry[i] ) === false ){
6 break;
7 }
8 }
9 };
10 each( [1,2,3,4,5], function ( i, n ) {
11 if( n>3 ){ // n 大于3的时候中止循环
12 return false;
13 }
14 console.log(n); // 输出 1 2 3
15 });
View Code
六、迭代器应用示例
目的:根据不同的浏览器获取相应的上传组件对象
将不同的上传对象封装到各自的函数里; 如果函数可用,则返回该对象,否则返回false,提示迭代器继续
1 // 将不同的上传对象封装到各自的函数里; 如果函数可用,则返回该对象,否则返回false,提示迭代器继续
2 var getActiveUploadObj = function(){
3 try{
4 return new ActiceXObject( "TXFTNActiveX.FTNUpload" ); // IE 上传控件
5 }catch(e){
6 return false;
7 }
8 };
9 var getFlashUploadObj = function(){
10 if( supportFlash() ){
11 var str = "<object type='application/x-shockwave-flash'></object>";
12 return $( str).appendTo( $("body") );
13 }
14 return false;
15 };
16 var getFormUpl0adObj = function(){
17 var str = "<input type='file' type='file' class='ui-file' />"; // 表单上传
18 return $( str).appendTo( $("body") );
19 };
View Code
//迭代器代码
1 //迭代器代码
2 var iteratorUploadObj = function(){
3 for( var i = 0, fn; fn = arguments[ i++ ]; ){
4 var uploadObj = fn();
5 if( uploadObj !== false ){
6 return uploadObj;
7 }
8 }
9 };
10
11 var uploadObj = iteratorUploadObj( getActiveUploadObj, getFlashUploadObj, getFormUpl0adObj );
View Code
七、总结
迭代模式相对简单,简单到很多时候我们不认为它是一种设计模式
阅读参考书籍 - << JavaScript 设计模式与开发实践 >>