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.
ObjectRange objects basically implement continuous numbers or strings, where Contains only one method, include, to determine whether a number or string is in the ObjectRange. And the ObjectRange object is also mixed with Enumerable methods, so you can directly call the methods in the Enumerable object on the ObjectRange object.
//Convenient method to create 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, when exclusive is true, the end value is not included. The default is undefined, which is equivalent to false
function initialize(start, end, exclusive) {
this.start = start;
this.end = end;
this.exclusive = exclusive;
}
//Override the _each method in Enumerable when traversing the ObjectRange object You need to use this method
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
};
})());
Look Let’s take an example and explain some details in detail:
$A ($R('a', 'e'))
// -> ['a', 'b', 'c', 'd', 'e'], no surprise there
//Do not try to output the results returned below, otherwise the browser will die directly
$A($R('ax', 'ba'))
// -> Ouch! Humongous array, starting as ['ax', 'ay', 'az', 'a{', 'a|', 'a}', 'a~'...]
Let’s talk about $A($R('a', 'e')) and how to return a value. Let’s first look at the $A method. The $A method has been explained in detail in the previous article [Prototype Learning - Tool Function Learning ($A Method)]. If you don’t know, please refer to it yourself. There is this sentence in the $A method: if ('toArray' in Object(iterable)) return iterable.toArray(); We know that ObjectRange is mixed with the methods in Enumerable, which means that the toArray method is indirectly implemented, so see Let’s take a look at the toArray method in Enumerable:
function toArray() {
return this.map();
}
//======> this.map()
//We noticed that when returning, the map method is mapped to the collect method
return {
//...
collect: collect,
map: collect,
// ...
}
//======> collect()
//In this case, this method is actually equivalent to returning an array, because passing All incoming parameters are undefined. There is a this.each method here, continue to look at
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 is overridden in ObjectRange. Use this method when traversing
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()
//Explain this._each() in detail
//The key is succ() method, because this method is used in _each to generate the next value.
//Where is this 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 won’t go into 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;
}
//In summary, if you want to define other types of ObjectRange objects, such as Date type, then you can You need to implement the succ() method yourself to generate continuous objects
The above process will be clear, but some functions are not explained in detail. When these objects are mentioned, the functions inside will be explained in detail. . Let’s look at a few examples of include:
$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