最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

jquery selectors for plain javascript objects instead of DOM elements - Stack Overflow

programmeradmin6浏览0评论

I've just started using jquery and I'm really enjoying using selectors. It occurs to me that the idiom would be a very nice way to traverse object trees (e.g., JSON query results). For example, if I have an object like this:

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

I would love to be able to write something like $('child baz:last', obj) and get 5. I recognize that chaining wouldn't work, but I'd still love the selection operator. Anyone know if such a beast exists, or what the easiest way would be to write one?

I've just started using jquery and I'm really enjoying using selectors. It occurs to me that the idiom would be a very nice way to traverse object trees (e.g., JSON query results). For example, if I have an object like this:

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

I would love to be able to write something like $('child baz:last', obj) and get 5. I recognize that chaining wouldn't work, but I'd still love the selection operator. Anyone know if such a beast exists, or what the easiest way would be to write one?

Share Improve this question edited Jul 17, 2009 at 17:42 Ateş Göral 140k27 gold badges141 silver badges191 bronze badges asked Jul 17, 2009 at 16:38 brendanbrendan 2,7431 gold badge20 silver badges13 bronze badges 2
  • Is there a reason that you don't like obj.child.baz[obj.child.baz.length-1]; ? – Justin Niessner Commented Jul 17, 2009 at 16:40
  • That'd work for this toy example, but breaks down quickly for deeper trees and larger objects. For example, I am working on a program that uses a tree representing network packets, and I'd love to be able to just write $('icmp [code=UNREACHABLE]', packetlist) to get the ICMP frames for unreachable packets. – brendan Commented Jul 17, 2009 at 16:46
Add a ment  | 

4 Answers 4

Reset to default 5

Here's a proof-of-concept implementation for getting jQuery itself work on objects. Through an object wrapper (FakeNode), you can trick jQuery into using its built-in selector engine (Sizzle) on plain JavaScript objects:

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

And the usage would be:

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

Giving the output:

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

Of course, you'd have to implement a lot more than the above to support more plex selectors.

BTW, have you seen jLinq?

The array object has some methods that you can use:

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

Some other examples:

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

Well, I'd personally say that pure object access looks better than jQuery-like queries. One thing that would be neat would be slicing and other filtering techniques.

If you really wanted to play with object access queries, the following would be some possibilities (think 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.

In the end though, I don't see how this is very useful. But eh, it's an idea I guess =)

simplest and easiest way is to wrap the element with jquery and then loop it by each

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 ); 
}
});
发布评论

评论列表(0)

  1. 暂无评论