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

    xiaoxiao2021-11-30  21

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

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

    自定义迭代器

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

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


    类似的还有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); });

    迭代器的种类

    迭代器有两种,一种是内部迭代器,另一种是外部迭代器 我们刚刚自己写的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); }));

    终止迭代器

    在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); });


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

    转载请注明原文地址: https://ju.6miu.com/read-679111.html

    最新回复(0)