Prototype source Analysis enumerable part (ii) _prototype

Source: Internet
Author: User
The previous each method dropped one aspect did not say, is the source of $break and $continue. These two variables are predefined and function as a function of the break and continue statements within the normal cycle. For efficiency reasons, it is not necessary to fully traverse a set (not limited to an array) in some operations, so break and continue are still essential.
For a loop, compare the following types of exit loops:
Copy Code code as follows:

var array_1 = [1,2,3];
var array_2 = [' A ', ' B ', ' C '];
(function () {
for (var i = 0, len = array_1.length i < len; i++) {
for (var j = 0, Len_j = array_1.length i < Len_j; J + +) {
if (' c ' = = Array_2[j]) {
Break
}
Console.log (Array_2[j]);
}
}
}) ();//a,b,a,b,a,b
(function () {
for (var i = 0, len = array_1.length i < len; i++) {
try{
for (var j = 0, Len_j = array_1.length i < Len_j; J + +) {
if (' c ' = = Array_2[j]) {
throw new Error ();
}
Console.log (Array_2[j]);
}
}catch (e) {
Console.log (' Exit a layer cycle ');
}
}
} ();//a,b, ' exit a layer of loops ', a,b, ' exit a cycle ', a,b, ' exit a layer of loops '
(function () {
try{
for (var i = 0, len = array_1.length i < len; i++) {
for (var j = 0, Len_j = array_1.length i < Len_j; J + +) {
if (' c ' = = Array_2[j]) {
throw new Error ();
}
Console.log (Array_2[j]);
}
}
}catch (e) {
Console.log (' Exit a layer cycle ');
}
}) ();//a,b, ' exit a layer of loops '

When we put the error capture at the corresponding loop level, we can interrupt the corresponding loop. You can implement the function of break and break label (GOTO). Such an application requirement is that the interrupt can be moved to the outside, just in line with the needs of the enumerable department.

Back to enumerable, because the nature of each (each = function (iterator, context) {}) method is a loop, and for its first argument iterator, it does not contain loops. Therefore, a direct call to the break statement will report a syntax error, so the prototype source code used in the second method above.
Copy Code code as follows:

Enumerable.each = function (iterator, context) {
var index = 0;
try{
This._each (function (value) {
Iterator.call (context, value, index++);
});
}catch (e) {
if (e!= $break) {
Throw e;
}
}
return this;
};

Once a $break is thrown in the iterator execution, the loop is interrupted. If it is not $break, then throw the corresponding error, the program also stable point. The definition of $break here has no special requirements, can be changed according to their own preferences, but not very meaningful.

Some of the methods in enumerable have already been implemented in some modern browsers (see the array of chrome native methods), and here is a comparison diagram:


When implementing these methods, you can use the native methods to improve efficiency. However, the source code does not borrow the original part, presumably because enumerable in addition to mixing the array part, but also need to mingle with other objects.

Looking at the diagram above, it is obvious that each and map are important, but the map is essentially each, except that each item in the collection is processed sequentially, and the map is based on each and returns the processed result. Within enumerable, the map is an alias for the Collect method, and the other alias is select, which uses the name collect.

Detection: All | any | Include

These three methods do not involve processing of the original collection, and the return value is a Boolean type.

All: Returns True if the elements in enumerable are all equivalent to True, otherwise returns false

Copy Code code as follows:

function All (iterator, context) {
var result = true;
This.each (function (value, index) {
result = Result &&!! Iterator.call (context, value, index);
});
return result;
}

For the all method, the two parameters are not required, so the interior provides a function to replace the iterator without the argument, returning the original value directly, the name is called PROTOTYPE.K. PROTOTYPE.K is defined at the beginning of the library, and is a function that returns the value of the parameter PROTOTYPE.K = functions (x) {return x;}. In addition, in the all method, as long as one of the items is treated as false, the entire process can be discarded (break), and the method of interrupting the loop at the beginning of this article is used. The final form is:
Copy Code code as follows:

PROTOTYPE.K = function () {};
Enumerable.all = function (iterator, context) {
iterator = Iterator | | PROTOTYPE.K;
var result = true;
This.each (function (value, index) {
result = Result &&!! Iterator.call (context, value, index);
if (!result) throw $break;
});
return result;
}

The final result returned is a Boolean that deviates from all, and we change the result:
Copy Code code as follows:

function collect (iterator, context) {
iterator = Iterator | | PROTOTYPE.K;
var results = [];
This.each (function (value, index) {
Results.push (Iterator.call (context, value, index));
});
return results;
}

At this point results is an array, we do not interrupt the process, save all the results and return, well, this is the Collect method, or the map method.


Any: Returns true if one or more of the elements in the enumerable are equivalent to true, otherwise returns false, and the principle is the same as all, and all is found to be false, and any is to be found true.
Copy Code code as follows:

function any (iterator, context) {
iterator = Iterator | | PROTOTYPE.K;
var result = false;
This.each (function (value, index) {
if (result =!!) Iterator.call (context, value, index))
Throw $break;
});
return result;
}

Include: To determine whether there is a specified object in the enumerable, based on the = = operator to compare this method has one step optimization, that is, call the IndexOf method, for the array, indexof return-1 can not know the corresponding element does not exist, If the collection has no IndexOf method, you can only find the alignment. Here the search and no algorithm, one by one, if you want to rewrite is also easy, but the usual application is not much, so it is not expected to spend this energy to optimize this. So if the result is true, the efficiency is higher than the result is false, see luck.
Copy Code code as follows:

function include (object) {
if (Object.isfunction (this.indexof))//The decision function should be familiar
if (This.indexof (object)!=-1) return true;//have indexOf directly call

var found = false;
This.each (function (value) {//Here's the problem of efficiency
if (value = = object) {
Found = true;
Throw $break;
}
});
return found;
}


Here's a set of methods for filtering data: Return a single element: Max | Min | Detect returns an array: grep | FindAll | Reject | Partition where Max and Min are not limited to numeric comparisons, character comparisons are the same. Max (iterator, context) can still carry two parameters, you can use iterator processing before comparing the value, the advantage is not to be limited to specific data types, for example, the object array according to a certain rule to the maximum value:
Copy Code code as follows:

Console.dir ([{Value:3},{value:1},{value:2}].max (function (item) {
return item.value;
}));//3

Therefore, the implementation of the source code can be imagined, direct comparisons, the implementation of the way can be as follows:
Copy Code code as follows:

function Max () {
var result;
This.each (function (value) {
if (result = NULL | | Value >= result)//result==null is the first time to compare
result = value;
});
return result;
}

After the extension, value is further changed to value = (The return value after iterator processing):
Copy Code code as follows:

function Max (iterator, context) {
iterator = Iterator | | PROTOTYPE.K;
var result;
This.each (function (value, index) {
Value = Iterator.call (context, value, index);
if (result = = NULL | | Value >= result)
result = value;
});
return result;
}

The principle of min is the same. Detect and any of the principles and approaches, any is to find a true return True,detect is to find a true to return the value that satisfies the true condition. The source code will not be posted. grep this is very familiar Ah, a unix/linux tool, its role is very familiar--is to return all and specified regular expression matching elements. Except that unix/linux can only handle strings, this extends the scope, but the basic form remains unchanged. If each item of the collection is a string, then the realization goes something like this:
Copy Code code as follows:

Enumerable.grep = function (filter) {
if (typeof filter = = ' String ') {
Filter = new REGEXP (filter);
}
var results = [];
This.each (function (value,index) {
if (Value.match (filter)) {
Results.push (value);
}
})
return results;
};

But one of the collections that is now to be processed may be a string, and in order to achieve a wider application, the first thing to consider is the invocation form. Look at the above implementation, pay attention to such a sentence:
if (Value.match (filter))
Where value is a string, match is a string method, now you want to extend the supported type, either add a match method to each value, or convert the form. Apparently the first bang was too big, the author converted the idea:
if (Filter.match (value))
So, regardless of value why, as long as the filter has a match method, the above for the RegExp object, there is no match method, so in the source code, the author extends the RegExp object:
RegExp.prototype.match = RegExp.prototype.test;
Note that match on the top and string match are essentially different. So, if value is an object, our filter only needs to provide the match method of the corresponding detection object. So there are:
Copy Code code as follows:

function grep (filter, iterator, context) {
iterator = Iterator | | PROTOTYPE.K;
var results = [];

if (object.isstring (filter))
Filter = new RegExp (Regexp.escape (filter));

This.each (function (value, index) {
if (Filter.match (value))//native filter does not have a match method.
Results.push (Iterator.call (context, value, index));
});
return results;
}

For the matching result, it can be processed and then returned, which is the function of the iterator parameter. Unlike the Max method, grep uses iterator to process the results during the primary operation, and Max uses iterator to process the source data before doing the main operation. Because the filter in grep replaces the role of iterator in Max. As for FindAll, is the enhanced version of grep, see Grep,findall is very simple. Reject is the twin version of FindAll, which works just the opposite. Partition is FindAll + Reject, combining the parent-child version. Reprint please indicate "http://www.cnblogs.com/xesam/" from Xiao Xi Shan zi

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.