Каковы наилучшие способы связывания ветвей структуры дерева JSON?

Итак, у меня есть JSON файл, который разбирается в объекте в Javascript. Я знаю, о чем вы думаете: счастливый парень. JSON по существу является блок-схемой в форме большого дерева. Здесь крошечный пример того, что я пытаюсь достичь:

tree = {
    "options": [
        {
            "options": [
                {
                    "name": "target",
                },
            ],
        },
        {
            "options": [
                {
                    "link": "...?",
                },
            ],
        },
    ]
}

Итак, в этом примере я буду глубоко во второй ветке (где он говорит "link"), и мне нужно будет перейти к ветке, содержащей "name": "target". Это JSON, помните, что он должен быть строкой (если там нет родной для ссылки?!), но я не знаю, как лучше отформатировать это.

Как я вижу, у меня есть хотя бы несколько вариантов.

  • Я мог бы искать. Если name был уникальным, я мог бы масштабировать дерево, ищущее элементы, пока не найду его. Я никогда не делал этого с Javascript раньше, но я ожидаю, что он будет медленным.

  • Я мог бы использовать путь навигации, например options:1:options:1, который описывает каждый ключ для пути. Опять же, я никогда не делал этого, но, предполагая, что ошибок нет, было бы намного быстрее. Как вы его реализуете?

Есть ли другие варианты, доступные мне? Что лучше? Есть ли способ распаковать это при расшифровке JSON или это рецепт для бесконечного цикла?

Ответ 1

Как насчет link: 'tree.options[0].options[0]', затем eval(path.to.link)?

Следующие образцы были протестированы только с помощью Chrome. Это же дерево для всех:

var tree = { level1: [{ key: 'value' }] };

Нет eval

function resolve(root, link) {
    return (new Function('root', 'return root.' + link + ';'))(root);
}

var value = resolve(tree, path.to.link);

Возврат к window

function resolve(root, link) {
    return (new Function(
        'root', 'return root.' + (link || root) + ';'
    ))(link ? root : window);
}

resolve(tree, 'level1[0].key'); // "value"
resolve('tree.level1[0].key'); // "value"

Ошибки улавливания

Блок try/catch предотвращает ошибочные ошибки от ошибок.

function resolve(root, path) {
    try {
        return (new Function('root', 'return root.' + path + ';'))(root);
    } catch (e) {}
}

resolve(tree, 'level1[0].key'); // "value"
resolve(tree, 'level1[1].key'); // undefined

Использование пользовательского формата пути

Хорошая часть здесь состоит в том, что мы можем передать либо объект, либо массив как root. Также обратите внимание, что мы можем заменить косую черту в path.split('/') любым char по нашему выбору.

function resolve(root, path) {
    path = '["' + path.split('/').join('"]["') + '"]';
    return (new Function('root', 'return root' + path + ';'))(root);
}

resolve(tree.level1, '0/key'); // "value"
resolve(tree, 'level1/0/key'); // "value"
resolve(tree, 'level1/0'); // Object {key: "value"}