Динамический глубокий выбор для объекта JavaScript - PullRequest
6 голосов
/ 27 июля 2010

С одним свойством это довольно просто:


var jsonobj = {
    "test": "ok"
}
var propname = "test";
// Will alert "ok"
alert(jsonobj[propname]);

Но я хочу использовать вложенное свойство:


var jsonobj = {
    "test": {
        "test2": "ok"
    }
}
var propname = "test.test2";
// Alerts undefined
alert(jsonobj[propname]);

Есть ли способ выбора вложенного"динамическое" свойство?Я знаю, что могу сделать jsonobj.test.test2, но проблема в том, что propname может измениться на свойство, которое имеет глубину 1,2 или 3 уровня.(например, test, test.test2, ...)

Ответы [ 4 ]

12 голосов
/ 27 июля 2010
function resolve(cur, ns) {

    var undef;

    ns = ns.split('.');

    while (cur && ns[0])
        cur = cur[ns.shift()] || undef;

    return cur;

}

например.

// 1:
resolve({
    foo: { bar: 123 }
}, 'foo.bar'); // => 123


// 2:
var complex = {
    a: {
        b: [
            document.createElement('div')
        ]
    }
};

resolve(complex, 'a.b.0.nodeName'); // => DIV

Преимущество использования этого в том, что оно не выдаст ошибку, если вы попытаетесь получить доступ к чему-то, что не существует - оно изящно вернет undefined.


EDIT:

В комментарии Энди упомянул, что это не приводит к ошибкам там, где это можно ожидать. Я согласен, что получение undefined является немного общим, и нет никакого способа определить, было ли ваше значение действительно разрешено. Итак, чтобы исправить это, попробуйте это:

var resolve = (function(){

    var UNRESOLVED = resolve.UNRESOLVED = {};
    return resolve;

    function resolve(cur, ns) {

        var undef;

        ns = ns.split('.');

        while (cur && ns[0])
            cur = cur[ns.shift()] || undef;

        if (cur === undef || ns[0]) {
            return UNRESOLVED;
        }

        return cur;

    }

}());

Он возвратит РАЗРЕШЕННЫЙ объект, который можно проверить следующим образом:

var result = resolve(someObject, 'a.b.c');

if (result === resolve.UNRESOLVED) {...}

Это не идеально, но это (IMO) лучший способ определить неразрешенное пространство имен без необходимости выдавать ошибки. Если вы хотите ошибок, просто продолжайте:

someObject.a.b.c; //...
3 голосов
/ 18 августа 2011

Я также реализовал это, используя внутреннюю рекурсивную функцию, например, так:

function get(obj, ns) {            

    function recurse(o, props) {
        if (props.length === 0) {
            return o;
        }
        if (!o) {
            return undefined;
        }
        return recurse(o[props.shift()], props);
    }

    return recurse(obj, ns.split('.'));
}

Это вернет глубокое значение свойства, указанного в параметре ns, в противном случае всегда будет возвращаться неопределенное, если оно не существует или есть какие-то проблемы на этом пути.

1 голос
/ 27 июля 2010

Вы можете написать небольшую функцию, чтобы разбить строку, а затем получить доступ к каждому фрагменту по очереди.Например:

function getProperty(propname, object)
{
    var props = propname.split('.');
    var obj = object;
    for (var i=0; i<props.length; i++)
    {
       obj = obj[props[i]];
    }
    return obj;
}

Очевидно, что для проверки наличия нулевых объектов, допустимых свойств и т. Д. Требуется немного больше кода

0 голосов
/ 27 июля 2010

Это работает, но довольно неудачно использует eval, поэтому я не рекомендую его использовать:

var jsonobj = {
    "test": {
        "test2": "ok"
    }
}
var propname = "test.test2";
alert(eval("jsonobj." + propname));
​

Попробуйте здесь: http://jsfiddle.net/TAgsU/

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...