Open EmberYu opened 5 years ago
迭代器模式是指提供一种方法顺序访问一个对象或者数组中的每个元素,而又不需要暴露该对象或数组的内部表示。在js语言中,早已有许多已经封装好的内置的迭代器,如数组的forEach,map,reduce,every,some。遍历时用到的关键字for in和es6的for of。
forEach,map,reduce,every,some
for in
for of
我们模拟jquery实现一个each函数,该函数接收两个参数,第一个是需要被循环的数组,第二个是循环中每个被循环的参数会触发的回调函数
function each (array, callback) { for (var i = 0; i < array.length; i ++) { callback.call(array[i], i, array[i]); // 把下标和值传递给callback } } each([1,2,3], function (index, value) { console.log(index, value); })
手动实现一个迭代器其实很简单,因为我们工作中只要用到了数组的方法,其实就相当于在使用迭代器
内部迭代器
内部迭代器在内部已经写好了迭代规则,外部只需要一次调用即可完成整个迭代过程,使用非常简单,但是由于内部规则已经实现,遇到新的需求可能就无法使用了。比如如果我们想要遍历两个数组判断是否相等,那么上面的each函数貌似就无法使用了
外部迭代器
外部迭代器必须显式地请求迭代下一个元素。增加了迭代器的灵活性,但是也增加了调用的复杂度
Iterator
ECMAScript 6新增的一种遍历机制,如果你的数据符合Iterator结构,那么就可以使用for of来进行遍历,而Iterator刚好就属于外部迭代器的一种,一个Iterator必须满足下面几个要求
next
value
done
// 模拟next方法的一个例子 var it = makeIterator(['a', 'b']); it.next() // { value: "a", done: false } it.next() // { value: "b", done: false } it.next() // { value: undefined, done: true } function makeIterator(array) { var nextIndex = 0; return { next: function() { return nextIndex < array.length ? {value: array[nextIndex++], done: false} : {value: undefined, done: true}; } }; }
使用外部迭代器,就可以实现刚才提到的遍历两个数组判断是否相等需求了
const mapArray = function (iterator1, iterator2) { if(iterator1.length !== iterator2.length) return false; let isDone = false; while (!isDone) { let a = iterator1.next(); let b = iterator2.next(); if (a.value !== b.value) return false; isDone = a.isDone || false; } return true; }
其实迭代器我们平时都有用过,掌握了迭代器模式后,可以尝试自己手动来实现数组对象已经封装好的一些方法,比如forEach,every,some,filter,reduce等,有空大家可以自己实现这些方法。加深对迭代器的理解
forEach
every
some
filter
reduce
迭代器同样可以减少分支的使用。在开发过程中,程序员最不愿意阅读的代码应该就是大量的分支语句了,因为为了确保每个分支做了什么事情,你不得不每个分支都要阅读。
比如常见的计算学生成绩是不及格,中等,优秀的情况
function calcStudent(score) { if (!score) throw new Error('请输入分数'); if (score < 60) { return '不及格' } else if (score < 80) { return '中等' } else { return '优秀' } }
如果学校要根据学生等级来颁发不同的奖品,那么我们又要在分支中的每个分支加多于的代码。时间久了这个函数承载的业务越来越多,那么每个分支都会变得很长,这样对于后期的维护是十分不利的。
使用迭代器来实现
const badStudent = function (score) { if (score < 60) { return '不及格 ' } return false; } const mediumStudent = function (score) { if (score < 80 && score >= 60) { return '中等 ' } return false; } const goodStudent = function (score) { if (score >= 80) { return '优秀' } return false; } const getStudentGrade = function (score) { const gradeLevels = [badStudent, mediumStudent, goodStudent]; for(var i = 0; i < arguments.length; i ++) { var studentGrade = fn(score); if (studentGrade !== false) { return studentGrade } } }
这种写法看起来比刚才那种多了许多,但是如果后期我们再增加新需求,只需要在相应的计算函数中去实现学生的业务逻辑,代码的可读性会变得更高。
迭代器模式是我们工作中最常用到的模式之一了。只要你用过数组,基本都有用过迭代器模式了。迭代器模式具有良好的解决分支过多导致代码不易阅读的能力,以后如果遇到你的代码有太多的if else,可以尝试使用迭代器来解决这个问题
迭代器模式
迭代器模式是指提供一种方法顺序访问一个对象或者数组中的每个元素,而又不需要暴露该对象或数组的内部表示。在js语言中,早已有许多已经封装好的内置的迭代器,如数组的
forEach,map,reduce,every,some
。遍历时用到的关键字for in
和es6的for of
。实现自己的迭代器
我们模拟jquery实现一个each函数,该函数接收两个参数,第一个是需要被循环的数组,第二个是循环中每个被循环的参数会触发的回调函数
手动实现一个迭代器其实很简单,因为我们工作中只要用到了数组的方法,其实就相当于在使用迭代器
迭代器的种类
内部迭代器
内部迭代器在内部已经写好了迭代规则,外部只需要一次调用即可完成整个迭代过程,使用非常简单,但是由于内部规则已经实现,遇到新的需求可能就无法使用了。比如如果我们想要遍历两个数组判断是否相等,那么上面的each函数貌似就无法使用了
外部迭代器
外部迭代器必须显式地请求迭代下一个元素。增加了迭代器的灵活性,但是也增加了调用的复杂度
Iterator
ECMAScript 6新增的一种遍历机制,如果你的数据符合
Iterator
结构,那么就可以使用for of
来进行遍历,而Iterator刚好就属于外部迭代器的一种,一个Iterator必须满足下面几个要求next
方法,可以将指针指向数据结构的下一个成员next
方法,可以将指针指向数据结构的第二个成员next
方法,直到它指向数据结构的结束位置next
方法,都会返回数据结构的当前成员的信息,其实就是一个包含value
和done
两个属性的对象。value
代表当前值,done
代表属性使用外部迭代器,就可以实现刚才提到的遍历两个数组判断是否相等需求了
迭代器的应用
其实迭代器我们平时都有用过,掌握了迭代器模式后,可以尝试自己手动来实现数组对象已经封装好的一些方法,比如
forEach
,every
,some
,filter
,reduce
等,有空大家可以自己实现这些方法。加深对迭代器的理解 迭代器同样可以减少分支的使用。在开发过程中,程序员最不愿意阅读的代码应该就是大量的分支语句了,因为为了确保每个分支做了什么事情,你不得不每个分支都要阅读。
比如常见的计算学生成绩是不及格,中等,优秀的情况
如果学校要根据学生等级来颁发不同的奖品,那么我们又要在分支中的每个分支加多于的代码。时间久了这个函数承载的业务越来越多,那么每个分支都会变得很长,这样对于后期的维护是十分不利的。
使用迭代器来实现
这种写法看起来比刚才那种多了许多,但是如果后期我们再增加新需求,只需要在相应的计算函数中去实现学生的业务逻辑,代码的可读性会变得更高。
总结
迭代器模式是我们工作中最常用到的模式之一了。只要你用过数组,基本都有用过迭代器模式了。迭代器模式具有良好的解决分支过多导致代码不易阅读的能力,以后如果遇到你的代码有太多的if else,可以尝试使用迭代器来解决这个问题