js中的设计模式之迭代器模式
迭代器模式
定义
迭代器模式是指提供一种方法顺序访问一个聚合对象中的各个元素,而又不需要暴露该对象的内部表示。
详细描述
迭代器使我们不用去关心访问对象的内部结构,就可以按照顺序去访问内部的每个元素,同时可以把迭代过程和业务逻辑抽离开来更加方便维护。更简单理解就是循环目标对象里的每一个值(如数组、对象等等),不用关心是怎么实现循环的,自己拿到值实现自己的业务逻辑。 迭代器又分为内部迭代器和外部迭代器。
-
内部迭代器:完全接手整个迭代过程,使用时只需要一次初始调用。 外部迭代器:内部暴露一些方法或者属性,需要使用者显式地请求迭代下一个元素。
内部迭代器
内部迭代器就是将迭代的过程封装在了内部,在使用的时候只需要初始调用一次迭代器函数,就会遍历目标对象里所有的元素。
// 迭代器函数 const loop = (data, callback) => { if (Array.isArray(data)) { const { length = 0 } = data; for (let index = 0; index < length; index++) { // 如果传入的callback返回值为false,跳出迭代 if (callback(data[index], index) === false) break; } } else { for (const key in data) { // 只迭代对象本身的属性 // callback返回值为false,跳出迭代 if (data.hasOwnProperty(key) && callback(data[key], key) === false) break; } } } // 使用迭代器迭代数组 loop([1,2,3,4], (item, i) => { if (item > 3) return false; console.log(item, i) }) // 1 0 // 2 1 // 3 2 // 使用迭代器迭代对象 loop({ a: 1, b:2, c: 3 }, (value, key) => { if (key === c) return false; console.log(value, key) }) // 1 a // 2 b
上述代码通过for循环实现了一个对数组、对象的迭代,使用的时候只需要将目标数据和自己的业务处理函数传入其中就可以循环调用,并且还可以通过函数的返回值来控制是否跳出迭代。其实在数组中已经有自带的方法(如foreach等),他们的思想模式是类似的。
外部迭代器
外部迭代器就是对象内部只暴露可以迭代的一些方法或者属性,使用时必须在外部显式地请求迭代下一个元素,而且需要使用者根据业务的场景手动的获取当前值和终止迭代。 外部迭代器增加了一些调用的复杂度,但相对也增强了迭代器的灵活性,我们可以手工控制 迭代的过程或者顺序。
// 外部迭代器 const Iterator = (data) => { let index = 0; // 指向下一项方法 const next = () => index += 1; // 是否结束方法 const isDone = () => index >= data.length; // 获取当前值方法 const getCurrentItem = () => data[index]; return { next, isDone, getCurrentItem } } // 使用外部迭代器 const iterator = Iterator([1,2,3]); while (!iterator.isDone()) { console.log(iterator.getCurrentItem()); iterator.next(); } // 1 // 2 // 3
上述代码中生成了一个外部迭代器暴露了三个方法next、isDone、getCurrentItem、当我们在外部对数据进行迭代的时候,需要根据业务场景手动的去调用这些方法来使用。
总结
迭代器模式大概分为外部迭代器和内部迭代器两种模式。外部迭代器调用比较复杂但是更加灵活,方便我们根据业务场景来灵活迭代。内部迭代器使用更为简单便捷,但是因为内部的迭代规则已经定义好,所以不够灵活。 这两种模式没有好坏之分而是分别适用于不同的业务场景,而且现在js中很多原生方法内部已经实现了迭代器模式(封装迭代器的方法还可以去参考阮一峰大佬书中关于迭代器的讲述)我们可以直接调用,所以我们应该在开发中借鉴迭代器模式的思想灵活的应用于项目代码中,而不是生搬硬套整个模式。