JavaScript: The Definitive Guide, Sixth Editio javaScript权威指南(第6版) pdf 文字版-文字版, javascript电子书, 和javascript 有关的电子书:

11.4.2 Iterators



11.4.2 Iterators

JavaScript 1.7 enhances the for/in loop with more general behavior. JavaScript 1.7’s for/in loop is more like Python’s for/in and allows it iterate over any iterable object. In order to understand this, some definitions are required.

An iterator is an object that allows iteration over some collection of values and maintains whatever state is necessary to keep track of the current “position” in the collection.

An iterator must have a next() method. Each call to next() returns the next value from the collection. The counter() function below, for example, returns an iterator that returns successively larger integers on each call to next(). Note the use of the function scope as a closure that holds the current state of the counter:

// A function that returns an iterator;

function counter(start) { let nextValue = Math.round(start); // Private state of the iterator return { next: function() { return nextValue++; }}; // Return iterator obj

}

let serialNumberGenerator = counter(1000); let sn1 = serialNumberGenerator.next(); // 1000 let sn2 = serialNumberGenerator.next(); // 1001

Iterators that work on finite collections throw StopIteration from their next() method when there are no more values to iterate. StopIterationis a property of the global object in JavaScript 1.7. Its value is an ordinary object (with no properties of its own) that is reserved for this special purpose of terminating iterations. Note, in particular, that StopIteration is not a constructor function like TypeError()or RangeError(). Here, for example, is a rangeIter() method that returns an iterator that iterates the integers in a given range:

// A function that returns an iterator for a range of integers

function rangeIter(first, last) { let nextValue = Math.ceil(first); return {

next: function() { if (nextValue > last) throw StopIteration; return nextValue++;

} }; }

// An awkward iteration using the range iterator. let r = rangeIter(1,5); // Get an iterator object while(true) { // Now use it in a loop

try {

console.log(r.next()); // Try to call its next() method } catch(e) {

if (e == StopIteration) break; // Exit the loop on StopIteration else throw e; } }

Note how awkward it is to use an iterator object in a loop where the StopIteration method must be handled explicitly. Because of this awkwardness, we don’t often use iterator objects directly. Instead we use iterable objects. An iterable object represents a collection of values that can be iterated. An iterable object must define a method named __iterator__() (with two underscores at the start and end of the name) which returns an iterator object for the collection.

11.4 Iteration | 275

The JavaScript 1.7 for/in loop has been extended to work with iterable objects. If the value to the right of the in keyword is iterable, then the for/in loop will automatically invoke its __iterator__() method to obtain an iterator object. It then calls the next() method of the iterator, assigns the resulting value to the loop variable, and executes the loop body. The for/in loop handles the StopIteration exception itself, and it is never visible to your code. The code below defines a range() function that returns an iterable object (not an iterator) that represents a range of integers. Notice how much easier it is to use a for/in loop with an iterable range than it is to use a while loop with a range iterator.

// Return an iterable object that represents an inclusive range of numbers

function range(min,max) {

return { // Return an object representing a range.

get min() { return min; }, // The range's bounds are immutable.

get max() { return max; }, // and stored in the closure.

includes: function(x) { // Ranges can test for membership.

return min <= x && x <= max;

},

toString: function() { // Ranges have a string representation.

return "[" + min + "," + max + "]";

},

__iterator__: function() { // The integers in a range are iterable.

let val = Math.ceil(min); // Store current position in closure.

return { // Return an iterator object.

next: function() { // Return next integer in the range.

if (val > max) // If we're past the end then stop.

throw StopIteration;

return val++; // Otherwise return next and increment.

}

};

}

};

}

// Here's how we can iterate over a range: for(let i in range(1,10)) console.log(i); // Prints numbers from 1 to 10

Note that that although you must write an __iterator__() method and throw a StopIteration exception to create iterable objects and their iterators, you are not expected (in normal use) to call the __iterator__() method nor to handle the StopIteration exception—the for/in loop does this for you. If for some reason you want to explicitly obtain an iterator object from an iterable object, call the Itera tor() function. (Iterator() is a global function that is new in JavaScript 1.7.) If the argument to this function is an iterable object, it simply returns the result of a call to the __iterator__()method, keeping your code cleaner. (If you pass a second argument to Iterator(), it will pass that argument on to the __iterator__() method.)

There is another important purpose for the Iterator() function, however. When you call it on an object (or array) that does not have an __iterator__() method, it returns a custom iterable iterator for the object. Each call to this iterator’s next() method returns an array of two values. The first array element is a property name, and the second is the value of the named property. Because this object is an iterable iterator, you can use it with a for/in loop instead of calling its next() method directly, and this means that you can use the Iterator() function along with destructuring assignment to conveniently loop through the properties and values of an object or array:

for(let [k,v] in Iterator({a:1,b:2})) // Iterate keys and values console.log(k + "=" + v); // Prints "a=1" and "b=2"

There are two other important features of the iterator returned by the Iterator() function. First, it ignores inherited properties and only iterates “own” properties, which is usually what you want. Second, if you pass true as the second argument to Iterator(), the returned iterator will iterate only property names, not property values. The following code demonstrates these two features:

欢迎转载,转载请注明来自一手册:http://yishouce.com/book/1/29673.html
友情链接It题库(ittiku.com)| 版权归yishouce.com所有| 友链等可联系 admin#yishouce.com|粤ICP备16001685号-1