2011-10-04 17 views
6

Al principio pensé que solo estaba asignando obj [0], obj [1], obj [2], etc. al objeto jQuery antes de devolverlo, y que la longitud es manualmente asignado. Pero no, dado que console.log registra una matriz y no un objeto.¿Cómo crea jQuery Array-Objects?

He echado un vistazo rápido a la fuente de jQuery, pero como no estoy familiarizado con ella, no la rompí fácilmente. jQuery.makeArray apareció primero, pero resultó ser lo contrario de lo que estoy buscando, en realidad se pierden los métodos del objeto al usarlo.

Mi primera suposición es iniciar primero la matriz y luego copiar todas las propiedades y métodos desde el objeto hasta la misma.

¿Alguien con experiencia en el código fuente de jQuery tiene una respuesta clara a esto?

+0

Supuestamente es similar a cómo 'NodeList' funciona como una matriz pero no lo es. – BoltClock

+0

¿Qué objetos de matriz? ¿Cómo se sabe que registra una matriz y no un objeto? –

Respuesta

5

Es tan simple como crear una nueva función y asignarle una nueva matriz como su prototipo.

function ArrayLike() {} 
ArrayLike.prototype = []; 

Así, por ejemplo:

function ArrayLike() {} 
ArrayLike.prototype = []; 
ArrayLike.prototype.fromArray = function(arr) { 
    for(var i = 0; i < arr.length; i++) 
     this.push(arr[i]); 
}; 
ArrayLike.prototype.foo = function() { 
    console.log("foo", this); 
}; 

var a = new ArrayLike(); 
a.fromArray([1, 2]); 
console.log(a); 
a.foo(); 

http://jsfiddle.net/Xeon06/fUgaf/

+0

Esto es notablemente resbaladizo. Voy a hacer una pregunta sobre una versión minimalista de esto. Gracias. – Manngo

13

jQuery crea lo que se llama (en el estándar ES) objetos similares a una matriz. En particular, tienen una propiedad de longitud, y también (que hace uso de la propiedad de longitud) tienen los elementos relevantes colocados bajo índices basados ​​en enteros.

Es tan simple como:

var arrayLike = {length: 3, 0:'first', 1:'second', 2:'third'}; 
Array.prototype.join.call(arrayLike, '|'); // "first|second|third" 

Si se echa un vistazo a the standard (15.4.4), en particular los métodos Array.prototype verá la siguiente nota debajo de todos y cada uno:

NOTA La función * es intencionalmente genérica; no requiere que este valor sea un objeto Array. Por lo tanto, se puede transferir a otros tipos de objetos para su uso como método. Si la función * puede aplicarse con éxito a un objeto host depende de la implementación.

Si nos fijamos en la descripción de estos algoritmos, que prácticamente sólo tiene que utilizar la propiedad length para iterar sobre el objeto (en nuestro caso un gama-como objeto) y acceder a los valores detrás de los enteros basados llaves. Por esa razón, son genéricos y trabajan en objetos js regulares con las propiedades relevantes.

Esencialmente eso es todo lo que hace jQuery (si mal no recuerdo el edificio está hecho en chisporroteo, el motor selector de css de jquery). Puedes probar esto/probarlo de varias maneras. Por ejemplo, Array un estándar JS realiza un poco de magia cuando la propiedad de longitud se acorta, pero el objeto jQuery no:

var arr = [1,2,3], $arr = $('div'); // assuming three divs 
arr.length=2; arr[2]; // undefined 
$arr.length=2; $arr[2]; // still references the div 

http://jsfiddle.net/cnkB9/

Así de makeArray jQuery convierte el jQuery gama-como objeto y marcas en una matriz js nativa real, pero como dijiste, entonces no tiene todos los métodos jquery adjuntos.

En cuanto a la razón por la que aparece en la consola, que se refieren a este excelente respuesta: What makes Firebug/Chrome console treat a custom object as an array? que explica que la presencia de la propiedad length y splice función permiten que aparezca como una matriz en la mayoría de consolas. Como se menciona, ese no es el caso en la consola web de FF4, que solo muestra que no es una matriz js nativa. Curiosamente, la función splice en realidad no tiene que funcionar, solo estar presente y ser una función.Por ejemplo:

>> console.log({length:2,0:'some',1:'thing',splice:new Function}); 
["some", "thing"] 
5

El siguiente código simple de cómo transformar una matriz devuelta por un selector de jQuery en funcionamiento con una variedad nativa de JavaScript:

var $arr = $('option'); // assuming three options 
var arr = Array.apply(null, $arr); 
// arr contains [option, option] 

Teniendo en cuenta el siguiente código HTML para el código anterior:

<html> 
    <head> 
     <script type="text/javascript" src="jquery-1.5.2.min.js"></script> 
    </head> 
    <body> 
     <select id="addSelection"> 
      <option value="Original Value">Original Value</option> 
      <option value="Two Value">Value two</option> 
      <option value="Three Value">Value three</option> 
     </select> 

     <br /> 

     <input id="btn" type="button" value="Changes" /> 
    </body> 
</hmtl>