Ranges represent an interval of values. The value type just needs to be "compatible," that is, to implement a succ method letting us step from one value to the next (its successor ).
Prototype provides such a method for Number and String, but you are of course welcome to implement useful semantics in your own objects, in order to enable ranges based on them.
The ObjectRange object basically implements a continuous number or string, which contains only one method, include, to determine whether a number or string is in ObjectRange. In addition, the ObjectRange object is also mixed with the Enumerable method, so you can directly call the methods in the Enumerable object on the ObjectRange object.
Copy codeThe Code is as follows:
// Convenient method for creating ObjectRange
Function $ R (start, end, exclusive ){
Return new ObjectRange (start, end, exclusive );
}
// Create an ObjectRange object and inherit from Enumerable
Var ObjectRange = Class. create (Enumerable, (function (){
// Initialization method. If exclusive is true, the end value is not included. The default value is undefined, which is equivalent to false.
Function initialize (start, end, exclusive ){
This. start = start;
This. end = end;
This. exclusive = exclusive;
}
// Overwrite the _ each method in Enumerable. This method is required when traversing ObjectRange objects.
Function _ each (iterator ){
Var value = this. start;
While (this. include (value )){
Iterator (value );
Value = value. succ ();
}
}
// Determine whether a value or string is included in the ObjectRange object
Function include (value ){
If (value <this. start)
Return false;
If (this. exclusive)
Return value <this. end;
Return value <= this. end;
}
Return {
Initialize: initialize,
_ Each: _ each,
Include: include
};
})());
Take a look at the example and explain the details in detail:
Copy codeThe Code is as follows:
$ A ($ R ('A', 'E '))
//-> ['A', 'B', 'C', 'D', 'E'], no surprise there
// Do not output the following results. Otherwise, the browser will die directly.
$ A ($ R ('ax ', 'ba '))
//-> Ouch! Humongous array, starting as ['ax ', 'ay', 'az', 'a {', 'a | ', 'a}', 'a ~ '...]
Here we will talk about $ A ($ R ('A', 'E') and how to return values. First, let's take A look at the $ A method. The previous article [Prototype Learning-tool function learning ($ A method)] has explained the $ A method in detail. If you do not know it, please refer to it. The $ A method contains the following: if ('toarray' in Object (iterable) return iterable. toArray (); we know that the methods in Enumerable are mixed into ObjectRange, that is, the toArray method is indirectly implemented. Let's take a look at the toArray method in Enumerable:
Copy codeThe Code is as follows:
Function toArray (){
Return this. map ();
}
// ======> This. map ()
// We noticed that the map method is mapped to the collect method when the returned result is returned.
Return {
//...
Collect: collect,
Map: collect,
//...
}
// ======> Collect ()
// In this example, this method is actually equivalent to returning an array, because the passed parameters are all undefined. This is the this. each method.
Function collect (iterator, context ){
Iterator = iterator | Prototype. K;
Var results = [];
This. each (function (value, index ){
Results. push (iterator. call (context, value, index ));
});
Return results;
}
// ======> This. each ()
// Finally, I saw this. _ each. Now I understand why the _ each method will be rewritten in ObjectRange. This method is used during traversal.
Function each (iterator, context ){
Var index = 0;
Try {
This. _ each (function (value ){
Iterator. call (context, value, index ++ );
});
} Catch (e ){
If (e! = $ Break) throw e;
}
Return this;
}
// ======> This. _ each ()
// Describe this. _ each () in detail ()
// The key is the succ () method, because _ each uses this method to generate the next value.
// Where is succ? This method is defined in Number. prototype and String. prototype.
Function _ each (iterator ){
Var value = this. start;
While (this. include (value )){
Iterator (value );
Value = value. succ ();
}
}
// I will not discuss the following two methods.
// ======> String. prototype. succ ()
Function succ (){
Return this. slice (0, this. length-1) +
String. fromCharCode (this. charCodeAt (this. length-1) + 1 );
}
// ======> Number. prototype. succ ()
Function succ (){
Return this + 1;
}
// To sum up, if you want to define other types of ObjectRange objects, such as Date, you must implement the succ () method to generate continuous objects.
The above process will be clear, but some functions are not carefully discussed. When talking about these objects, we should carefully describe the functions in them. Let's take a look at several examples of include:
Copy codeThe Code is as follows:
$ R (1, 10). include (5)
//-> True
$ R ('A', 'H'). include ('x ')
//-> False
$ R (1, 10). include (10)
//-> True
$ R (1, 10, true). include (10)
//-> False