Definition 1.

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 structure.

2. Iterators in jQuery

The iterator pattern is nothing more than a loop through the elements of an aggregate object. For example, the $. Each function in jQuery, where I is the current index and n is the current element

$.each([1.2.3].function(i, n) {
    console.log('Current subscript :' + i);
    console.log('Current value :' + n);
});
Copy the code

Implement an iterator

Implement an each function that takes two arguments, the first being the array to be looped through and the second being the callback to be fired after each step in the loop:

var each = function(ary, callback) {
    for(var i=0, l = arr.length; i< l; i++){
        callback.call(ary[i], i, ary[i])
    }
}

each([1.2.3].function(i,n){
    alert([i,n]);
})
Copy the code

4. Inner and outer iterators

Iterators can be divided into inner iterators and outer iterators

4.1 Inner iterators

The each function written above is an internal iterator. The internal iteration rules of each function have been defined. It takes over the entire iteration process completely, and only one initial call is required externally.

Internal iterators are very convenient to use. The outside world does not care about the implementation inside the iterator. The interaction with the iterator is only an initial call, but this is also the disadvantage of internal iterators. Since the rules for iterating inner iterators have been specified in advance, the each function above cannot iterate over two arrays at the same time.

For example, to determine whether the values of two arrays are exactly the same, if you do not rewrite each, you have to start with the callback function of each

var compare = function(ary1, ary2) {
     if(ary1.length ! == ary2.length) {throw new Error('ary1 is not equal to ary2 ')
     }
     each(ary1, function(i, n){
         if(n ! == ary2[i]) {throw new Error('ary1 is not equal to ary2 ')}}); alert('ary1 is equal to ary2 ')
}

compare([1.2.3], [1.2.4]);
Copy the code

This compare function implementation is not elegant

4.2 External iterators

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 iterators to manually control the process or order of iteration

var Iterator = function(obj) {
    var current = 0;
    
    var next = function(){
        current += 1;
    }
    
    var isDone = function(){
        return current >= obj.length
    }
    
    var getCurrItem = function(){
        return obj[current];
    }
    
    return {
        next: next,
        isDone: isDone,
        getCurrItem: getCurrItem,
        length: obj.length
    }
}

var compare = function(iterator1, iterator2){
    if(iterator1.length ! == iterator2.length){throw new Error(Iterator1 and iterator2 are not equal);
    }
    while(! iterator1.isDone() && ! iterator2.isDone()) {if(iterator1.getCurrItem() ! == iterator2.getCurrItem()){throw new Error(Iterator1 and iterator2 are not equal);
        }
        iterator1.next();
        iterator2.next();
    }
    
    alert(Iterator1 is equal to iterator2)}var iterator1 = Iterator([1.2.3])
var iterator2 = Iterator([1.2.3])

compare(iterator1, iterator2)
Copy the code

Although external iterators are called in a relatively complex way, they are more widely applicable and can meet more changeable needs. There is no better internal iterator than external iterator in actual production, and the choice of which to use depends on the requirements scenario

5. Iterate over array and literal objects

The iterator pattern can iterate not only over arrays, but also over some array-like objects. Arguments {“0″: ‘a’,”1”:’b’}, etc. An inner or outer iterator can be iterated over as long as the iterated aggregate object has the length attribute and can be accessed with subscript

In JavaScript, a for in statement can be used to iterate over properties of ordinary literal objects.

6. Inverse-order iterators

The iterator pattern provides a way to loop through each element of an aggregate object, but it does not specify whether to loop through the aggregate object in order, backward, or middle order.

var reverseEach = function(ary, callback) {
    for(var l=ary.length - 1; l>=0; l--) {
        callback(i, ary[l]);
    }
}

reverseEach([0.1.2].function(i,n){
    console.log(n);
})
Copy the code

7. Abort the iterator

An iterator can provide a way out of the loop just like a break in a normal for loop.

var each = function(ary, callback) {
    for(var i=0, l = arr.length; i< l; i++){
        if (callback(i, ary[i]) === false) {
            break;
        }
    }
}

each([1.2.3.4.5].function(i,n){
    if(n>3) {
        return false
    }
    console.log(n)
})
Copy the code

8. Application examples of iterator pattern

Priority usage: For example, priority A > B > C

Not using the iterator pattern:

var fun = function() {
    if (a) {
        return 'Concrete code'
    } else if (b) {
        return 'Concrete code'
    } else {
        return 'Concrete code'}}Copy the code

The downside: the function is full of if conditional branches, which are hard to read and violate the open and close principle. If you want to add more methods later, you have to add more conditional branches to fun

Use the iterator pattern: Wrap each method in its own function, and then use an iterator to iterate over the objects until one is available

var a = function(){
    if(a) {
        return 'Concrete code'
    }
    return false
}

var b = function(){
    if(b) {
        return 'Concrete code'
    }
    return false
}

var c = function(){
    if(c) {
        return 'Concrete code'
    }
    return false
}
Copy the code

All three functions have the same convention: if the object inside the function is available, the function returns that object, otherwise returns false, prompting the iterator to continue iterating

The iterator only needs to do these steps

  • Provide a method that can be iterated so that a, B, and C are iterated over in order of priority
  • If the function being iterated returns an object, the correct object was found, and if the function returns false, the iterator continues
var iteratorObj = function(){
    for(var i=0, fn; fn=arguments[i++];) {
        var obj = fn();
        if(obj ! = =false) {returnobj; }}}var obj = iteratorObj(a,b,c)
Copy the code

After refactoring the code, the methods for retrieving different objects are separated into separate functions, and the if branches are no longer entangled, making it easy to maintain and extend the code.

9. Summary

The iterator pattern is a relatively simple pattern, and most languages have iterators built in