The iterator pattern refers to providing a way to sequentially access individual elements in an aggregated object without exposing the Object's internal Representation. The iterator pattern separates the iterative process from the business logic, and after using the iterator pattern, you can access each of these elements sequentially, even if you do not care about the internal construction of the Object.
one, internal iterators and external iterators
1. Internal iterators
The internal iterator function internally has defined the iteration rules, which take over the entire iterative process, with only one initial call from the Outside.
An internal iterator is very handy when it is called, and the outside of the iterator is not concerned with the internal implementation of iterators, and the interaction with iterators is only an initial call, but this is also the disadvantage of an internal iterator.
vareach =function(ary, Callback) { for(vari = 0, L = ary.length; I < l; i++) {callback.call (ary[i], i, ary[i]);//pass subscripts and elements as parameters to the callback function } }; varCompare =function(iterator1, Iterator2) { while(!iterator1.isdone () &&!Iterator2.isdone ()) { if(iterator1.getcurritem ()!==Iterator2.getcurritem ()) { Throw NewError (' Iterator1 and Iterator2 not equal ' ); } Iterator1.next (); Iterator2.next (); } alert (' Iterator1 and Iterator2 equal ' ); } varIterator1 = Iterator ([1, 2, 3 ] ); varIterator2 = Iterator ([1, 2, 3 ] ); Compare (iterator1, iterator2); //output: Iterator1 and Iterator2 equal
2. External iterators
An external iterator must explicitly request an iteration of the next Element.
External iterators increase the complexity of some calls, but they also enhance the flexibility of iterators, and we can manually control the process or order of Iterations.
//External iterators varIterator =function(obj) {varCurrent = 0; varNext =function() { current+ = 1; }; varIsDone =function(){ returnCurrent >=obj.length; }; varGetcurritem =function(){ returnobj[current]; }; return{next:next, isdone:isdone, getcurritem:getcurritem}}; //Compare arrays for the same varCompare =function(iterator1, Iterator2) { while(!iterator1.isdone () &&!Iterator2.isdone ()) { if(iterator1.getcurritem ()!==Iterator2.getcurritem ()) { Throw NewError (' Iterator1 and Iterator2 not equal ' ); } Iterator1.next (); Iterator2.next (); } alert (' Iterator1 and Iterator2 equal ' ); } varIterator1 = Iterator ([1, 2, 3 ] ); varIterator2 = Iterator ([1, 2, 3 ] ); Compare (iterator1, iterator2); //output: Iterator1 and Iterator2 equal
second, iterative class array objects and Literal objects
Whether an internal iterator or an external iterator, as long as the aggregated object being iterated has the length attribute and can be accessed with subscript, it can be iterated. array, object, Arguments.
Example of application of iterator mode
The following method is based on different browsers to obtain the corresponding upload component object, because using the browser upload control to upload fast, can pause and resume, so we first use the control Upload. If the browser does not install the upload control, then use flash upload, if not even flash installed, then you have to use the Browser's native form Upload.
varGetuploadobj =function(){ Try{ //IE Upload Control return NewActiveXObject ("txftnactivex.ftnupload"); }Catch(e) {if(supportflash ()) {//the Supportflash function does not provide varstr = ' <object type= ' application/x-shockwave-flash ' ></object> '; return$ (str). appendTo ($ (' body ')) ); }Else{ //form Upload varstr = ' <input name= ' "file" type= "file"/> '; return$ (str). appendTo ($ (' body ')) ); } } };
The Getuploadobj function is flooded with try,catch and if conditional branching. The disadvantage is Obvious. The first is difficult to read, the second is a serious breach of the open and closed Principle. In the development and debugging process, we need to switch back and forth different upload methods, each change is quite painful. Later we added support for some additional upload methods, such as HTML5 upload, the only way is to continue to add conditional branches to the Getuploadobj Function.
We encapsulate each method of acquiring a upload object in its own function, and then use an iterator to iterate over the upload object until it gets to a usable one:
//IE Upload Control varGetactiveuploadobj =function(){ Try{ return NewActiveXObject ("txftnactivex.ftnupload" ); }Catch(e) {return false; } }; //the Supportflash function does not provide varGetflashuploadobj =function(){ if(supportflash ()) {varstr = ' <object type= ' application/x-shockwave-flash ' ></object> '; return$ (str). appendTo ($ (' body ')) ); } return false; }; //form Upload varGetformupladobj =function(){ varstr = ' <input name= ' file ' type= ' file ' class= ' Ui-file '/> '; return$ (str). appendTo ($ (' body ')) ); }; //iterators varIteratoruploadobj =function(){ for(vari = 0, fn; fn = arguments[i++ ]; ){ varUploadobj =fn (); if(uploadobj!==false ){ returnuploadobj; } } }; varUploadobj = iteratoruploadobj (getactiveuploadobj, getflashuploadobj, getformupladobj);
In the 3 functions of getactiveuploadobj, getflashuploadobj, getformupladobj, there is the same convention: if the upload object inside the function is available, let the function return the object, and conversely return false, prompting The iterator continues to iterate Back.
JavaScript Design Patterns and development practice iterator patterns