2009-07-17 20 views
6

Właśnie zacząłem używać jquery i naprawdę lubię używać selektorów. Przyszło mi do głowy, że idiom będzie bardzo dobrym sposobem na przechodzenie przez drzewa obiektów (np. Wyniki zapytania JSON). Na przykład, jeśli mam obiektu takiego:selektory jquery dla zwykłych obiektów javascript zamiast elementów DOM

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

Bardzo chciałbym, aby móc napisać coś jak $ („baz dziecko: ostatni”, obj) i dostać 5. uznaję, że nie łańcuchowym pracować, ale nadal uwielbiam operatora selekcji. Czy ktoś wie, czy istnieje taka bestia, czy jak najprościej byłoby ją napisać?

+0

Czy istnieje jakiś powód, że nie lubisz obj.child.baz [obj.child.baz.length -1]; ? –

+0

To by działało na ten zabawny przykład, ale szybko się psuje dla głębszych drzew i większych obiektów. Na przykład pracuję nad programem, który używa drzewa reprezentującego pakiety sieciowe i chciałbym móc po prostu napisać $ ("icmp [code = UNREACHABLE]", lista pakietów), aby uzyskać ramki ICMP dla pakietów nieosiągalnych. – brendan

Odpowiedz

5

Oto implementacja proof-of-concept, aby uzyskać samą pracę jQuery na obiektach. Poprzez owinięcie obiektu (FakeNode), można oszukać jQuery do korzystania wbudowanym silnikiem wybieraka (Sizzle) na zwykłym obiektów 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)); 
} 

I wykorzystanie byłoby:

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

Nadanie wyjście:

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

Oczywiście, aby obsłużyć bardziej skomplikowane selektory, musisz wdrożyć o wiele więcej niż wyżej.

BTW, czy widziałeś jLinq?

+0

To bardzo urocze, dzięki! I nie widziałem też jLinqa. – brendan

+0

To jest bardzo interesująca odpowiedź. – ken

0

Przedmiotem tablica ma kilka metod, które można użyć:

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

Kilka innych przykładów:

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

Dzięki. Tak, to jest to, co teraz robię. Ale selektory są moim zdaniem o wiele potężniejsze, ponieważ nie musisz znać dokładnego kształtu konkretnego obiektu, który chodzisz, aby znaleźć interesujące elementy. Myślę, że istnieje dobry powód, dla którego jquery nie powoduje, że robisz html.body.table [1] .tr ... – brendan

0

Cóż, ja osobiście powiedzieć, że czysta dostęp obiekt wygląda lepiej niż jak jQuery zapytania. Jedną rzeczą, która byłaby zgrabna, byłoby krojenie i inne techniki filtrowania.

Jeśli naprawdę chciał grać z zapytaniami Object Access dodaje byłoby pewne możliwości (myślę 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. 

w końcu chociaż, ja nie wiem, jak to jest bardzo użyteczne. Ale eh, to jest idea, którą zgaduję =)

0

najprostszym i najłatwiejszym sposobem jest owinąć element z jQuery i następnie pętli go za każdym

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); 
} 
}); 
Powiązane problemy