2009-07-17 12 views
6

Ho appena iniziato a utilizzare jquery e mi diverto molto con i selettori. Mi viene in mente che l'idioma sarebbe un modo molto piacevole per attraversare gli alberi degli oggetti (ad es. Risultati delle query JSON). Per esempio, se ho un oggetto come questo:selettori jquery per oggetti javascript semplici invece di elementi DOM

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

mi piacerebbe essere in grado di scrivere qualcosa come $ ('baz bambino: ultima', obj) e ottenere 5. riconosco che sarebbe concatenamento non lavoro, ma mi piacerebbe ancora l'operatore di selezione. Qualcuno sa se esiste una tale bestia o quale sarebbe il modo più semplice per scriverne una?

+0

C'è un motivo che non ti piace obj.child.baz [obj.child.baz.length -1]; ? –

+0

Funzionerebbe per questo esempio di giocattolo, ma si rompe rapidamente per alberi più profondi e oggetti più grandi. Ad esempio, sto lavorando a un programma che utilizza un albero che rappresenta i pacchetti di rete e mi piacerebbe essere in grado di scrivere solo $ ('icmp [code = UNREACHABLE]', packetlist) per ottenere i frame ICMP per i pacchetti non raggiungibili. – brendan

risposta

5

Ecco un'implementazione proof-of-concept per far funzionare jQuery stesso sugli oggetti. Attraverso un involucro oggetto (FakeNode), si può ingannare jQuery ad utilizzare la sua built-in del motore di selezione (Sizzle) sulla pianura oggetti 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)); 
} 

E l'utilizzo sarebbe:

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"); 

Dare la uscita:

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

Naturalmente, si avrebbe dovuto implementare molto di più di quanto sopra per sostenere selettori più complesse.

BTW, hai visto jLinq?

+0

È molto carino, grazie! E neanche io avevo visto jLinq. – brendan

+0

Questa è una risposta molto interessante. – ken

0

L'oggetto array ha alcuni metodi che è possibile utilizzare:

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

Alcuni altri esempi:

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

Grazie. Sì, questo è quello che faccio ora. Ma i selezionatori sono molto più potenti a mio parere, perché non devi conoscere la forma esatta dell'oggetto in particolare che stai camminando per trovare elementi interessanti. Penso che ci sia una buona ragione per cui jquery non ti fa fare html.body.table [1] .tr ... – brendan

0

Beh, io personalmente dire che l'accesso oggetto puro sembra meglio di jQuery-like interrogazioni. Una cosa che sarebbe pulita sarebbe affettare e altre tecniche di filtraggio.

Se si voleva davvero a giocare con le domande di accesso agli oggetti, il seguente sarebbe qualche possibilità (si pensi 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. 

Alla fine, però, io non vedere come questo è molto utile. Ma eh, è ​​un'idea suppongo =)

0

modo più semplice e più facile è quello di avvolgere l'elemento con jQuery e poi loop da ogni

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); 
} 
}); 
Problemi correlati