“This is the 31st day of my participation in the August Gwen Challenge.

preface

At the advanced end of the interview, there are often some questions about design patterns, and the answers are not good. Coincides with the activities of more challenges in August, I plan to spend a month to clarify the knowledge points about design patterns, to increase the confidence of my interview.

define

The iterator pattern provides a way to access the elements of an aggregate object sequentially without exposing the internal representation of the object. The iterator pattern separates the process of iterating from the business logic. After using the iterator pattern, each element of an object can be accessed sequentially, even without caring about its internal construction.

The iterator pattern is a very simple design pattern. It’s so simple that most of the time we don’t think of it as a design pattern because most languages today have iterators built in, such as array.prototype.foreach in JavaScript.

implementation

The implementation of the iterator pattern is very simple, as shown below

const each = (ary, callback) => { for (let i = 0, l = ary.length; i < l; i++) { callback.call(ary[i], i, ary[i]); }}; each([1, 2, 3], function (i, n) { console([i, n]); });Copy the code

The iterator pattern is that each element of the ARY array is passed into the callback for processing.

Inner iterators and outer iterators

Iterators can be divided into internal iterators and external iterators. Each function implemented above belongs to the internal iterator. The internal iteration rules of each function have been defined and it takes over the entire iteration process completely.

So now there is a requirement to construct a function to compare the contents of ary1 and ary2. Can be implemented using each function. Of course it can, as follows:

const compare = (ary1, ary2) => { if (ary1.length ! == ary2.length) {throw new Error('ary1 and ary2 are not equal '); } each(ary1, function (i, n) { if (n ! == ary2[I]) {throw new Error('ary1 and ary2 are not equal '); }}); Console. log('ary1 and ary2 are equal '); }; compare( [ 1, 2, 3 ], [ 1, 2, 5 ] ); // 'ary1 and ary2 are not equal ';Copy the code

However, this implementation is too inelegant. The iteration rules in each are already defined internally and cannot be changed, which is also the disadvantage of internal iterators.

To implement compare elegantly inside, we use an external iterator. An external iterator must explicitly request iteration of the next element. External iterators add some complexity to the calls, but they also increase the flexibility of the iterators, allowing us to manually control the iteration process or sequence.

Now we implement compare using an external iterator.

const Iterator = function (obj) { let current = 0; const next = function () { current += 1; }; const isDone = function () { return current >= obj.length; }; const getCurrItem = function () { return obj[current]; }; return { next: next, isDone: isDone, getCurrItem: getCurrItem } }; const compare = function (iterator1, iterator2) { while (! iterator1.isDone() && ! iterator2.isDone()) { if (iterator1.getCurrItem() ! == iterator2.getCurrItem()) {throw new Error(' Iterator1 and iterator2 are not equal '); } iterator1.next(); iterator2.next(); } console.log('iterator1 is equal to iterator2 '); } const iterator1 = Iterator([1, 2, 3]); const iterator2 = Iterator([1, 2, 3]); compare(iterator1, iterator2); Iterator1 is equal to iterator2Copy the code

The Iterator function is an external Iterator that returns an object that exposes a getCurrItem method to explicitly request iterating over the next element.

Although external iterators are called in a relatively complex way, they are more widely applicable and can meet more changeable needs.

How to terminate an iteration

Very simple, just say return false where you want to terminate.