As noted by OP, there is no statement after the while
condition. Note the semicolon after the while loop, return this
is only run after the while loop has been completed, and that is when any one of the three statements evaluate to false. If all you want to know is how the while loop is working, Filip Bartuzi's answer is probably the most complete. I will attempt to give a broader answer as to what the each2
method does.
As noted in the docs, it is just a more efficient version of jQuery's #each, or Array.prototype.forEach or Underscore's #each or lodash's #forEach that is designed specifically for select2's uses. It is used to iterate over any array or other iterable, wrapped in a jQuery object. So it is used for arrays of strings as well as jQuery collections.
The way it works is the scope (this
) is the array that it was called on. It is given a function as an argument. This is exactly how the other each
methods I previously mentioned are called. The function provided to each2
is called once for each item in the array. The while loop is sort of a hacky way to iterate over each item in the array, and call the function, setting the item as the context and passing the index in the array and the item as a jQuery object as the first and second arguments. Each statement in the while
loop condition must be evaluated to determine if it is true, and that process is being used to actually assign values to variables, and increment i
. The c.call(j[0], i, j) !== false
part allows the function to terminate the loop early by returning false. If the function returns false, the while loop will stop, otherwise it will continue until i
is greater than l
, meaning that every item in the array has been used. Returning this
afterwards just enables another method to be chained to the array after .each2
.
Basically the while
loop could be rewritten to:
var j = $([0]), i = 0, l = this.length, continue = true;
while (i < l) {
i++;
j.context = j[0] = this[i];
continue = c.call(j[0], i, j);
if (!continue) {
break;
}
}
but there are probably some performance reasons why that can't be optimized as well by the browser.
It is more fragile than the normal each
methods. For example if an element in the array has a falsey value such as 0
, (j.context = j[0] = this[i])
will be falsey, causing the loop to terminate. But it is only used in the specialized cases of the select2 code, where that shouldn't happen.
Let's walk through a couple of examples.
function syncCssClasses(dest, src, adapter) {
var classes, replacements = [], adapted;
classes = $.trim(dest.attr("class"));
if (classes) {
classes = '' + classes; // for IE which returns object
$(classes.split(/\s+/)).each2(function() {
if (this.indexOf("select2-") === 0) {
replacements.push(this);
}
});
}
...
^ This code is getting the classes from a dest
DOM element. The classes are split into an array of strings (the string is being split on whitespace characters, that's the \s+
regular expression), each class name is an item in the array. No special jQuery work is needed here, so the 2 arguments that the function called by each2
is provided are not used. If the class starts with 'select2-' the class is added into a array called replacements
. The 'select2-' classes are being copied, pretty simple.
group.children=[];
$(datum.children).each2(function(i, childDatum) { process(childDatum, group.children); });
^ For brevity I have not included the rest of this method, but it is part of the process
method. In this case, each2
is being used to recursively process
a node and all it's children. $(datum.children)
is a jQuery selection, each 'child' (named childDatum
) will be processed in turn, and it's children will go through the same process. The group.children
array will be used as a collection, whatever is added to that array for each childDatum
will be available, so after the each2
is run it will hold everything that has been added during the processing of all the children, grandchildren, etc.