浅析JavaScript设计模式——迭代器模式

迭代器模式
提供一种方法顺序访问一个聚合对象中的各个元素,而又不需要暴露该对象的内部表示

迭代器模式不像我们上次讲的代理模式
它十分简单,简单到我们可能都不认为它是一种设计模式
因为我们现在使用的语言基本上内部都实现了自己的迭代器
迭代器可以抽取内部的逻辑,我们不需要知道对象内部长什么样
就可以按顺序访问它内部的元素

自定义迭代器

ES5中给我们的数组扩展了很多原型方法、
其中就有一个好用的迭代器forEach
它的参数是一个函数,函数的参数分别是值、索引、数组引用
它会按顺序遍历数组的每一个元素,并且执行函数

var arr = ['a','b','c','d','e'];
arr.forEach(function(value, index, arr){
    console.log(value, index, arr);
});

浅析JavaScript设计模式——迭代器模式_第1张图片


类似的还有jQuery框架中的$.forEach静态函数

$.forEach([1,2,3,4,5],funciton(index,value){
    //...
});

我们也可以通过原生的for循环来仿照这个功能定义自己的迭代器
实现起来也是非常简单
就几行代码

var each = function(arr, fn){ //我们自己自定义的迭代器
    for(var i = 0, l = arr.length; i < l; i++){
        fn.call(arr[i], i, arr[i]);
    }
};
var arr = ['a','b','c','d','e'];
each(arr, function(index, value){
    console.log('当前索引:' + index);
    console.log('当前值:' + value);
}); 

浅析JavaScript设计模式——迭代器模式_第2张图片

迭代器的种类

迭代器有两种,一种是内部迭代器,另一种是外部迭代器
我们刚刚自己写的each函数就属于内部迭代器
为什么叫内部迭代器呢?
因为我们的each函数内部定义了迭代规则,
只需要执行一次函数,它会自己去遍历数组元素,执行回调函数
就是因为这样,
内部迭代器有着使用简单粗暴的优点
同时有着不可以改变迭代规则的缺点
(但我觉得一般情况下内部迭代器就足够满足我们的需求了)
而外部迭代器必须显式地请求下一次要迭代的元素
外部迭代器使用复杂但是它更加灵活
到底是使用内部迭代器还是外部迭代器完全按需求来定
由于外部迭代器很少用,所以我举一个更适用于适用外部迭代器例子来比较两种迭代器

内部迭代器

我要实现一个这样的功能
通过迭代器比较两个数组中所装的元素是否完全相等
我们先来尝试使用内部迭代器(使用我们自定义的each函数)

var compare = function(arr1, arr2){
    if(arr1.length !== arr2.length){
        return false;
    }
    var bFlag = true;
    each(arr1, function(index, value){
        if(value !== arr2[index]){
            bFlag = false;
        }
    });
    return bFlag;
}

由于我们的each函数规则已经制定了
所以我们不能同时遍历两个数组
如果想完成我们的任务,就只能对each回调函数做手脚了
可以看到通过内部迭代器实现这样的功能实在不好看
而且勉强实现了功能还多亏在我们JavaScript可以把函数作为参数传递

外部迭代器

内部迭代器我们使用了自定义的each函数
外部迭代器我们也同样需要自己来实现一个
完整代码如下

var Iterator = function(arr){
    var cur = 0; //当前索引
    var next = function(){ //指向下一位索引
        cur++;
    };
    var isOver = function(){ //判断是否结束
        return cur > arr.length - 1;
    };
    var getCurItem = function(){ //获取当前值
        return arr[cur];
    };
    return {
        next: next,
        isOver: isOver,
        getCurItem: getCurItem
    }
}
var compare = function(arr1, arr2){
    var ite1 = Iterator(arr1);
    var ite2 = Iterator(arr2);
    while(!ite1.isOver() || !ite2.isOver()){
        if(ite1.getCurItem() !== ite2.getCurItem()){
            return false;
        }
        ite1.next();
        ite2.next();
    }
    return true;
}

可以看到我们定义的外部迭代器可以更优雅地解决问题
外部迭代器更加灵活,可以解决多变的需求

倒序迭代器

下面我要说的并不是什么新迭代器
都属于外部迭代器,只不过我们改变一些内部规则
比如这个超级简单的倒序迭代器,稍微改变一些代码分分钟实现

var revEach = function(arr, fn){
    for(var i = arr.length - 1; i >= 0; i--){
        fn.call(arr[i], i, arr[i]);
    }
};
console.log(revEach(['a','b','c'],function(index, value){
    console.log('当前索引:' + index);
    console.log('当前值:' + value);
}));

浅析JavaScript设计模式——迭代器模式_第3张图片

终止迭代器

在jQuery框架中的$.each()迭代器中的回调函数中有约定
如果返回false,那么就终止迭代
这样的变化就更方便了,我们改变一下我们最初写的each函数

var each = function(arr, fn){
    for(var i = 0, l = arr.length; i < l; i++){
        if(fn.call(arr[i], i, arr[i]) === false){
            break;
        }
    }
};
each([1,2,3,4,5],function(index, value){
    if(value > 3){ //如果值大于3就终止迭代
        return false;
    }
    console.log(value);
});


今天的迭代器模式就写到这里了
说是设计模式
感觉就是写了一篇自定义迭代器的文章

你可能感兴趣的:(Web前端,JavaScript-ES3,JS设计模式)