【问题标题】:jquery selectors for plain javascript objects instead of DOM elements用于纯 javascript 对象而不是 DOM 元素的 jquery 选择器
【发布时间】:2009-07-17 16:38:31
【问题描述】:

我刚刚开始使用 jquery,我非常喜欢使用选择器。我突然想到,这个成语将是一种非常好的遍历对象树的方式(例如,JSON 查询结果)。例如,如果我有这样的对象:

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

我希望能够编写像 $('child baz:last', obj) 这样的东西并得到 5。我认识到链接不起作用,但我仍然喜欢选择运算符。有谁知道这样的野兽是否存在,或者最简单的方法是什么?

【问题讨论】:

  • 有不喜欢obj.child.baz[obj.child.baz.length-1]的原因吗? ?
  • 这适用于这个玩具示例,但对于更深的树和更大的对象来说很快就会崩溃。例如,我正在开发一个使用树表示网络数据包的程序,我希望能够编写 $('icmp [code=UNREACHABLE]', packetlist) 来获取无法访问数据包的 ICMP 帧。

标签: javascript jquery css-selectors


【解决方案1】:

这是一个让 jQuery 本身在对象上工作的概念验证实现。通过对象包装器 (FakeNode),您可以诱使 jQuery 在纯 JavaScript 对象上使用其内置的选择器引擎 (Sizzle):

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

而用法是:

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

给出输出:

选择器:child baz - 发现:3,4,5 选择器:酒吧 - 发现:2 - 找到:[对象对象] - 发现:3

当然,要支持更复杂的选择器,您必须实现比上述更多的功能。

顺便说一句,你见过jLinq吗?

【讨论】:

  • 这是一个非常有趣的答案。
【解决方案2】:

数组对象有一些你可以使用的方法:

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

其他一些例子:

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

【讨论】:

  • 谢谢。是的,这就是我现在所做的。但在我看来,选择器的功能要强大得多,因为您不必知道正在行走的特定对象的确切形状即可找到有趣的元素。我认为 jquery 不让你做 html.body.table[1].tr... 是有充分理由的
【解决方案3】:

好吧,我个人认为纯对象访问看起来比类似 jQuery 的查询更好。切片和其他过滤技术是一种简洁的方法。

如果您真的想玩对象访问查询,以下是一些可能性(想想 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.

最后,我不明白这有什么用处。但是,嗯,我猜这是一个想法 =)

【讨论】:

    【解决方案4】:

    最简单最简单的方法是用jquery包装元素,然后逐个循环

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

    【讨论】:

      猜你喜欢
      • 2023-04-02
      • 2011-03-01
      • 2022-10-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多