2009-07-17 12 views
6

Acabo de empezar a usar jquery y realmente disfruto usando los selectores. Se me ocurre que la expresión idiomática sería una forma muy agradable de recorrer árboles de objetos (por ejemplo, resultados de consultas JSON). Por ejemplo, si tengo un objeto como éste:selectores jquery para objetos simples javascript en lugar de elementos DOM

var obj = { 'foo': 1, 'bar': 2, 
      'child': { 'baz': [3, 4, 5] } 
      }; 

Me gustaría ser capaz de escribir algo como $ ('baz niño: pasado, obj) y obtener 5. Reconozco que no sería encadenamiento trabajo, pero aún me encantaría el operador de selección. Alguien sabe si existe tal bestia, o ¿cuál sería la forma más fácil de escribir una?

+0

¿Hay una razón por la que no le gusta obj.child.baz [obj.child.baz.length -1]; ? –

+0

Eso funcionaría para este ejemplo de juguete, pero se descompone rápidamente para árboles más grandes y objetos más grandes. Por ejemplo, estoy trabajando en un programa que usa un árbol que representa paquetes de red, y me encantaría poder escribir $ ('icmp [code = UNREACHABLE]', packetlist) para obtener los marcos ICMP para los paquetes inalcanzables. – brendan

Respuesta

5

Aquí hay una implementación de la prueba de concepto para hacer que jQuery funcione en los objetos. A través de un envoltorio objeto (FakeNode), se puede engañar a jQuery en el uso de su motor incorporado de selección (Arden) en la llanura objetos JavaScript:

function FakeNode(obj, name, parent) { 
    this.obj = obj; 
    this.nodeName = name; 
    this.nodeType = name ? 1 : 9; // element or document 
    this.parentNode = parent; 
} 

FakeNode.prototype = { 
    documentElement: { nodeName: "fake" }, 

    getElementsByTagName: function (tagName) { 
     var nodes = []; 

     for (var p in this.obj) { 
      var node = new FakeNode(this.obj[p], p, this); 

      if (p === tagName) { 
       nodes.push(node); 
      } 

      Array.prototype.push.apply(nodes, 
       node.getElementsByTagName(tagName)); 
     } 

     return nodes; 
    } 
}; 

function $$(sel, context) { 
    return $(sel, new FakeNode(context)); 
} 

Y el uso sería:

var obj = { 
    foo: 1, 
    bar: 2, 
    child: { 
     baz: [ 3, 4, 5 ], 
     bar: { 
      bar: 3 
     } 
    } 
}; 

function test(selector) { 
    document.write("Selector: " + selector + "<br>"); 

    $$(selector, obj).each(function() { 
     document.write("- Found: " + this.obj + "<br>"); 
    }); 
} 

test("child baz"); 
test("bar"); 

Dando la salida:

 
Selector: child baz 
- Found: 3,4,5 
Selector: bar 
- Found: 2 
- Found: [object Object] 
- Found: 3 

Por supuesto, se tendría que aplicar mucho más que el anterior para apoyar los selectores más complejas.

BTW, ¿has visto jLinq?

+0

¡Eso es muy lindo, gracias! Y tampoco había visto jLinq. – brendan

+0

Esta es una respuesta muy interesante. – ken

0

El objeto de matriz tiene algunos métodos que se pueden utilizar:

last = obj.child.baz.slice(-1)[0]; 

Algunos otros ejemplos:

first = obj.child.baz.slice(0,1)[0]; 
allExceptFirst = obj.child.baz.slice(1); 
allExceptLast = obj.child.baz.(0,-1); 
+0

Gracias. Sí, eso es lo que hago ahora. Pero los selectores son mucho más poderosos en mi opinión, porque no tienes que saber la forma exacta del objeto en particular que estás caminando para encontrar elementos interesantes. Creo que hay una buena razón por la que jquery no hace que hagas html.body.table [1] .tr ... – brendan

0

Bueno, yo personalmente diría que el acceso a objetos pura se ve mejor que jQuery parecido consultas. Una cosa que estaría bien sería cortar y otras técnicas de filtrado.

Si realmente quería jugar con consultas de acceso a objetos, lo siguiente sería pensar en algunas posibilidades (XPath):

var obj = { 
    foo: 1, 
    bar: 2, 
    child: { 
     foo: { 
      baz: [3, {a: 1}, {a: 2, b: 3}]}, 
     bar: { 
      baz: [42, {a: 123}, {a: -1}]}, 
     baz: null}}; 

// Implicitly start in the Global object, unless a context is provided. 
// Keys in JavaScript objects are essentially stored in order (not valid for 
// *all* flavors, but it's close to standard. So you could do slicing on keys.) 

// Selects (does not return them) 
// obj.child.foo.baz[1].a 
// obj.child.foo.baz[2].a 
// obj.child.bar.baz[1].a 
// obj.child.bar.baz[2].a 
// Then performs an aggregate that returns value 125. 
$('obj.child[:2].baz[1:].a').sum() 

// Selects obj.foo, obj.bar, obj.child.foo.baz[0] and obj.child.bar.baz[0] 
$('obj *[typeof(number)]') 

// Selects obj.foo and obj.child.foo 
$('obj foo') 

// Other possible methods: delete(), set(), get() (as an array of values), 
// min(), max(), avg(), merge() etc etc. 

En el final, sin embargo, no veo cómo esto es muy útil. Pero eh, es una idea, supongo =)

0

manera más simple y más fácil es envolver el elemento con jQuery y luego bucle por cada

var obj = { 'foo': 1, 'bar': 2, 
     'child': { 'baz': [3, 4, 5] } 
     }; 

$(obj).each(function(){ 
console.log(this); 
if(this.hasOwnProperty('foo')) 
{ 
    console.log("hey i found " + this.foo); 
} 
}); 
Cuestiones relacionadas