Select2 each2 method - how does it work?

I looked through Select2 ( source ) and found a prototype of each2 method:

$.extend($.fn, { each2 : function (c) { var j = $([0]), i = -1, l = this.length; while ( ++i < l && (j.context = j[0] = this[i]) && c.call(j[0], i, j) !== false //"this"=DOM, i=index, j=jQuery object ); return this; } }); 

My question is: how does this method work? I mean - why does a while loop exist only with a condition, without a part of the statement? I would really like to understand this flow of methods.

+6
source share
3 answers

When you put an expression inside a condition (for example: if (i) , if (i == null) , if (++i) , if (i < 2) )) the expression is evaluated before its 'checked' is true or false

Real-time example:

we have var i = 0 ; now you call if (++i) console.log(i) . The expression ++i returns 1 (this is understood as true in javascript [ 0 not ]), therefore console.log(i) logs 1 .

Now let's say that we have var i = 0 and if (++i && ++i) console.log(i) . The first expressions return 1 , so the second is also called, which returns 2 . Both 1 and 2 are treated as true, therefore console.log(i) logs 2

Tall. Let's look at the same example as above, but before if we initialize var i = -1 , Now let's call if (++i && ++i) console.log(i) . The first ++i returns 0 , which is false.

To continue, you must learn how && works. Let me explain quickly: if you add exp1 && exp2 && exp3 ... && expX , then exp2 will be executed (evaluated) only when exp1 returns true (for example: true , 1 , "some string" ). exp3 will only be executed if exp2 is true, exp4 when exp3 is true, etc .... (until we press expN )

Now back to f (++i && ++i) console.log(i) . So the first ++i returns 0 , which is false, so the second ++i not satisfied, and the whole condition is false , so console.log(i) will not be executed (once the increment has been completed, so i now 0 )

Now that you get it, I can tell you that the while works the same way in condition checking. For example, var = -2 and while (++i) will be executed until ++i returns false (i.e. 0 ). while (++1) will execute exactly 2 times.

TL DR BELOW !!!

So how does it work?

  while ( ++i < l && (j.context = j[0] = this[i]) && c.call(j[0], i, j) !== false ); 

I think the best way to explain is to rewrite it (:

  while ( ++i < l ) { if (!(j.context = j[0] = this[i])) break; if (!(c.call(j[0], i, j) !== false)) break; } 

or less magical:

  var i = 0; while ( i < l ) { if (!(j.context = j[0] = this[i])) break; if (!(c.call(j[0], i, j) !== false)) break; i++; } 
+4
source

The purpose of the code is to add a new each2 function to a jQuery object, which works similarly to .each . Using this .each2 function .each2 similar to the .each function that runs on a jQuery object, takes a function to call back with 2 arg (index and value), and returns a jQuery object.

Mysterious while loop,

 while ( ++i < l && (j.context = j[0] = this[i]) && c.call(j[0], i, j) !== false //"this"=DOM, i=index, j=jQuery object ); return this; } 

Remarks:

  • Continues "only if" all 3 conditions evaluate to true
  • The first condition: ++i < l , a simple iteration takes true until the value of i is less than the number of selected elements. [ i initialized to -1 , due to the use of ++i in the next line and i used as an index in subsequent links]
  • The second condition: this is an initialization check + null / undefined. The condition evaluates to true for all valid values ​​and fails if there is an invalid context.
  • Third condition: The purpose of this condition allows you to exit the loop if the callback function returns false. Same as .each , where return false inside the function will interrupt the iteration.
+3
source

As OP noted, there is no statement after the while condition. Pay attention to the semicolon after the while loop, return this only starts after the while loop completes, and this means that any of the three statements evaluates to false. If all you want to know is how the while loop works, Philip Bartuzi's answer is probably the most comprehensive. I will try to give a broader answer about what each2 method each2 .

As noted in the docs, this is a more efficient version of jQuery #each or Array.prototype.forEach or Underline #each or lodash #forEach , which is specifically designed to use select2. It is used to iterate over any array or other iterable wrapped in a jQuery object. Therefore, it is used for string arrays, as well as for jQuery collections.

How it works, the ( this ) area is the array on which it was called. He is given a function as an argument. This is the name of the other methods each , which I mentioned earlier. The function provided by each2 is called once for each element of the array. The while loop is a kind of hacker way of iterating over each element of the array and calling the function, setting the element as context and passing the index in the array, and the element as a jQuery object as the first and second arguments. Each statement in the condition of the while must be evaluated to determine if it is true, and this process is used to actually assign values ​​to variables and increment i . The c.call(j[0], i, j) !== false allows the function to break the loop earlier, returning false. If the function returns false, the while loop will stop, otherwise it will continue until i is greater than l , which means that each element of the array is used. Returning this after this simply allows you to bind another method to the array after .each2 .

In principle, the while can 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 that cannot be optimized by the browser.

It is more fragile than the usual each methods. For example, if the element in the array is false, for example 0 , (j.context = j[0] = this[i]) will be false, which will end the loop. But it is used only in specialized cases of select2 code, where this should not be.

Skip some 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 gets classes from the dest DOM element. Classes are divided into an array of strings (the string is divided into space characters, which is the regular expression \s+ ), each class name is an element in the array. There is no special jQuery work here, so 2 arguments are not used, which is the function called by each2 . If the class begins with 'select2-', the class is added to the array named replacements . The "select2-" classes are copied, quite simply.

 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 used for the recursive process a node and all its children. $(datum.children) is a jQuery choice, each "child" (named childDatum ) will be processed one at a time, and children will go through the same process. The array group.children will be used as a collection, everything that is added to this array for each childDatum will be available, so after each2 it will contain everything that was added during processing of all children, grandchildren, etc.

+1
source

Source: https://habr.com/ru/post/977094/


All Articles