jQuery merge () y array.length tipo de datos

He estado buscando a través de la fuente jQuery y me encontré con la function de merge . Aquí está el código fuente para ello:

 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; } 

Mientras entiendo el código, algo no tiene sentido para mí. Particularmente la parte if (typeof l === "number") . He intentado pasar una matriz a esta function cuando .length manualmente la propiedad .length a algo así como "3" y verifiqué su tipo, y sigo obteniendo un tipo de number .

Mi pregunta es cuándo la propiedad de length nunca sería un tipo de number en matrices de JavaScript.

La function de merge que estás viendo es un método jQuery público: jQuery.merge() o $.merge() . Entonces, podría pensar que leer la documentation de jQuery.merge() arrojaría algo de luz sobre esta pregunta.

Desafortunadamente, no es así, al less hasta este momento.

Como se explica en las otras respuestas y comentarios, esta testing para una propiedad de length numérica siempre tendrá éxito cuando el second sea ​​una Array , porque una Array siempre tendrá una length numérica. La única razón posible para tener esta testing en el código es manejar el caso donde el second no es una Array .

Pero la documentation no menciona este caso en absoluto. Solo trata los casos en los que el first y el second son objects Array nativos de JavaScript, no objects "tipo array".

Si este uso documentado fue todo lo que hizo esta function, sería bastante inútil, ya que JavaScript proporciona un método perfectamente perfecto de array.concat(array) que se puede utilizar en lugar de jQuery.merge() .

Por lo tanto, parece que el verdadero propósito de esta function debe estar en su uso no documentado . Probémoslo en la console de Chrome en la página jQuery.merge () doc . Abra las herramientas de desarrollador, select la pestaña Consola e ingrese un ejemplo similar al del documento:

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

y luego testing lo mismo con .concat() :

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

Ambos registrarán exactamente lo mismo:

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

Como esto es jQuery, el caso más probable de un object "tipo array" sería un object jQuery. Por ejemplo, esa página doc actualmente tiene tres elementos <h3> , por lo que podemos getlos con:

 $('h3') 

Eso se registrará:

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

Eso no es una matriz, pero se parece mucho a una, y tiene una propiedad de length numérica con la que podemos verificar:

 typeof $('h3').length 

Entonces concat con concat :

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

Oops. Eso debería darnos una matriz de cuatro elementos, 'x' seguidos por los tres elementos DOM. En cambio, me da una matriz de dos elementos, con el object jQuery como el segundo elemento:

 [►e.fn.init[3] ] 

Parece que el object "de tipo array" de jQuery no es lo suficientemente parecido a una matriz para .concat() .

Curiosamente, algunos otros methods de matriz funcionan con el object de jQuery similar a una matriz, como .slice() :

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

Eso registra el resultado correcto, una matriz de dos elementos:

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

Así que $.merge() :

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

Efectivamente, eso registra lo que esperábamos:

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

También hay otra forma de hacer esto. jQuery proporciona un método .toArray() , por lo que podemos hacer lo mismo combinando eso con .concat() :

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

Eso registra lo mismo que la $.merge() .

¿Qué pasa si first es un object jQuery?

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

Eso también funciona:

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

Por lo tanto, parece que este es el propósito de este método: realizar operaciones tipo array.concat() en objects jQuery.

¡Pero espera! Esto todavía no responde la pregunta de por qué ese código adicional está ahí para la .length no numérica. Después de todo, un object jQuery tiene un .length numérico, por lo que todavía no hemos ejercido el código para el caso no numérico.

Por lo tanto, esta parte del código debe estar allí para algún fin que no sea ​​el event handling objects jQuery. ¿Qué podría ser eso?

Podemos encontrar un poco más yendo al repository fuente de jQuery y ubicando el file en el directory src que tiene el código merge: (es core.js ). Luego use el button de Culpa y busque dentro de la página para el código de merge: para ver cuál es el comentario de confirmación para el código. Nuevamente, el código que nos preguntamos ahora es la cláusula else , donde typeof l no es un número.

El compromiso fue por John Resig en 2009-12-09, con un comentario "Rewrote merge () (más rápido y less obtuso ahora). Fixed # 5610." Hay un poco de controversia en la discusión en esa página:

Bueno, su versión es más rápida solo en el caso especial (muy raro) de una propiedad de longitud sobreescrita. En todos los demás casos, el mío fue un poco más rápido. Además, no estás considerando el caso obj.length = new Number (N) – pero sí, no es tan relevante, supongo.

Esto ayuda a explicarlo un poco, pero ¿cuál es el problema # 5610? Quizás eso nos diga. ¿No ve un rastreador de problemas en el repository de GitHub? jQuery tiene su propio rastreador de problemas y si buscamos allí el #5610 (o hacemos una búsqueda en Google del jquery issue 5610 de jquery issue 5610 , finalmente encontramos el número 5610 :


MAKEARRAY PUEDE CAUSAR ACCIDENTE DE NAVEGADOR EN OBJETOS DE ARRANQUE CON PROPIEDAD DE LONGITUD

Descripción

No he probado esto con 1.4

Para un object con una propiedad de longitud que arroje a un integer positivo distinto de cero, makeArray creará una matriz con esa longitud completada con indefinido.

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

Si la propiedad de longitud es cero, negativa o decimal, entonces Firefox y Safari se cuelgan. (FF muestra el error de script que no responde, Safari se cuelga hasta que se bloquea)

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

Podría estar pasando un object a la function, por ejemplo

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

si el segundo es undefined o null o un object que no admite longitud, l no será un número. No puedo decir por qué el segundo puede ser indefinido o nulo, ya que está siendo pasado de la persona que llama.