JQuery merge () and array.length data types

I was looking through some of the jQuery source and I came across a merge function. Here is the source code for it:

 function merge(first, second) { var l = second.length, i = first.length, j = 0; if (typeof l === "number") { for (; j < l; j++) { first[i++] = second[j]; } } else { while (second[j] !== undefined) { first[i++] = second[j++]; } } first.length = i; return first; } 

As long as I understand the code, this makes no sense to me. In particular, the if (typeof l === "number") part if (typeof l === "number") . I tried passing an array to this function when I manually changed the .length property to something like "3" and checked its type, and I still get the number type.

My question is when will the length property never be a number type in JavaScript arrays?

+4
source share
3 answers

The merge function you are looking at is a public jQuery method: jQuery.merge() or $.merge() . So you might think that reading the jQuery.merge() documentation might shed some light on this question.

Unfortunately, this is not the case, at least at the time of this writing.

As explained in other answers and comments, this test for the length numeric property will always succeed if second is Array , because Array will always have the length numeric. The only possible reason for this test in the code is to handle the case when second not Array .

But the documentation does not mention this case at all. It discusses only cases where both first and second are native JavaScript Array objects, and not array-like objects.

If this documented use was all this function, it would be useless since JavaScript provides a very nice native method of array.concat(array) , which can be used instead of jQuery.merge() .

Thus, it would seem that the real purpose of this function should be in undocumented use. Try it in the Chrome console at jQuery.merge () doc . Open the developer tools, select the Console tab and enter an example similar to the one in the document:

 jQuery.merge( [ 'a', 'b' ], [ 'c', 'd' ] ) 

and then try the same with .concat() :

 [ 'a', 'b' ].concat([ 'c', 'd' ]) 

They will both record the same thing:

 ["a", "b", "c", "d"] 

Since this is jQuery, the most likely case of an array object is a jQuery object. For example, on this doc page there are now three <h3> elements, so we can get them with:

 $('h3') 

This will be log:

 [►<h3>…</h3>, ►<h3>…</h3>, ►<h3>…</h3>] 

It is not an array, but it is very similar to one, and it has a numeric property length , which we can check with:

 typeof $('h3').length 

So try using concat :

 ['x'].concat( $('h3') ) 

Unfortunately. This should give us an array of four elements: "x", followed by three DOM elements. Instead, I give us an array of two elements, and a jQuery object as the second element:

 [►e.fn.init[3] ] 

It looks like a jQuery object like an array is not enough for an array for .concat() .

Oddly enough, some other array methods work with jQuery type .slice() , for example .slice() :

 Array.prototype.slice.call( $('h3'), 1 ) 

This writes the correct result, an array of two elements:

 [►<h3>…</h3>, ►<h3>…</h3>] 

So try $.merge() :

 $.merge( ['x'], $('h3') ) 

Of course, this is what we expected:

 ["x", ►<h3>…</h3>, ►<h3>…</h3>, ►<h3>…</h3>] 

There is another way to do this. jQuery provides the .toArray() method, so we can do the same by combining it with .concat() :

 ['x'].concat( $('h3').toArray() ) 

This writes the same as calling $.merge() .

What if first is a jQuery object?

 $.merge( $('h1'), $('h3') ) 

This also works:

 [<h1 class="entry-title">jQuery.merge()</h1>, ►<h3>…</h3>, ►<h3>…</h3>, ►<h3>…</h3>] 

So, it looks like this is the goal of this method: perform array.concat() -like jQuery objects.

But wait! This still does not answer the question why this extra code exists for non-numeric .length . After all, the jQuery object has a numerical value .length , so we still haven't used the code for the non-numerical case.

So this piece of code should be there for some purpose other than handling jQuery objects. What could it be?

We can learn a little more by going to the jQuery source repository and finding the file in the src directory, which has merge: (this happens to be core.js ). Then use the Blame button and search the page for the merge: code to see that there is a commit comment for the code. Again, the code we're interested in right now is the else clause, where typeof l not a number.

The final was John Resig in 2009-12-09, with the comment "Rewoted merge () (faster and less dumb now). Fixed # 5610." There is a bit of controversy in the discussion on this page:

Well, your version is faster only in a special (very rare case) case of overwriting the length property. In all other cases, mine was a little faster. Also, you do not consider the case of obj.length = new Number (N) - but yes, it is not so important, I suppose.

This explains this a bit, but what is problem number 5610? Maybe it will tell us. Don't you see problem tracking in the GitHub repository? jQuery has its own bug tracker , and if we search #5610 (or do a google search for jquery issue 5610 , we will finally find issue # 5610 :


MAKEARRAY MAY BELIEVE BROWSER ON CONSCIOUSNESS OBJECTS WITH LENGTH OBJECTS

Description

I have not tested this with 1.4

For an object with a length property that distinguishes a nonzero positive integer, makeArray will create an array with a length filled with undefined.

 >>> jQuery.makeArray({'length': '5'}) [undefined, undefined, undefined, undefined, undefined] 

If the length property is zero, negative, or decimal, then Firefox and Safari freeze. (FF shows an unresponsive script error, Safari freezes until it crashes)

 >>> jQuery.makeArray({'length': '0'}) >>> jQuery.makeArray({'length': '5.2'}) >>> jQuery.makeArray({'length': '-3'}) 
+3
source

You can pass an object to a function, for example.

 merge ({ length: 'mylength' }, { length: 'mylength' }); 
0
source

if the second is undefined or null or an object that does not support length, l will not be a number. I can’t say why the second one can be undefined or null since it is passed from the caller.

0
source

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


All Articles