Найдите ключом глубоко во вложенном объекте

Скажем, у меня есть объект:

[
    {
        'title': "some title"
        'channel_id':'123we'
        'options': [
                    {
                'channel_id':'abc'
                'image':'http://asdasd.com/all-inclusive-block-img.jpg'
                'title':'All-Inclusive'
                'options':[
                    {
                        'channel_id':'dsa2'
                        'title':'Some Recommends'
                        'options':[
                            {
                                'image':'http://www.asdasd.com'                                 'title':'Sandals'
                                'id':'1'
                                'content':{
                                     ...

Я хочу найти один объект, где идентификатор равняется 1. Существует ли функция для чего-то вроде этого? Я мог использовать Подчеркивание _.filter метод, но я должен был бы запустить наверху и отфильтровать.

58
задан 18 August 2016 в 10:25

5 ответов

Улучшенный ответ @haitaka, с помощью ключа и предиката

function  deepSearch (object, key, predicate) {
    if (object.hasOwnProperty(key) && predicate(key, object[key]) === true) return object

    for (let i = 0; i < Object.keys(object).length; i++) {
      if (typeof object[Object.keys(object)[i]] === "object") {
        let o = deepSearch(object[Object.keys(object)[i]], key, predicate)
        if (o != null) return o
      }
    }
    return null
}

, Таким образом, это может быть вызвано как:

var result = deepSearch(myObject, 'id', (k, v) => v === 1);

или

var result = deepSearch(myObject, 'title', (k, v) => v === 'Some Recommends');

Вот jsFiddle: http://jsfiddle.net/ktdx9es7

3
ответ дан 1 November 2019 в 14:21

Другая (несколько глупая) опция состоит в том, чтобы использовать естественно рекурсивную природу JSON.stringify и передать ее функция заменителя , который работает на каждом вложенном объекте во время процесса stringification:

const input = [{
  'title': "some title",
  'channel_id': '123we',
  'options': [{
    'channel_id': 'abc',
    'image': 'http://asdasd.com/all-inclusive-block-img.jpg',
    'title': 'All-Inclusive',
    'options': [{
      'channel_id': 'dsa2',
      'title': 'Some Recommends',
      'options': [{
        'image': 'http://www.asdasd.com',
        'title': 'Sandals',
        'id': '1',
        'content': {}
      }]
    }]
  }]
}];

console.log(findNestedObj(input, 'id', '1'));

function findNestedObj(entireObj, keyToFind, valToFind) {
  let foundObj;
  JSON.stringify(input, (_, nestedValue) => {
    if (nestedValue && nestedValue[keyToFind] === valToFind) {
      foundObj = nestedValue;
    }
    return nestedValue;
  });
  return foundObj;
};
2
ответ дан 1 November 2019 в 14:21

Улучшенный ответ для принятия во внимание циклических ссылок в объектах. Это также отображает путь, который это взяло для получения там.

В этом примере, я ищу iframe, который я знаю, где-нибудь в глобальном объекте:

const objDone = []
var i = 2
function getObject(theObject, k) {
    if (i < 1 || objDone.indexOf(theObject) > -1) return
    objDone.push(theObject)
    var result = null;
    if(theObject instanceof Array) {
        for(var i = 0; i < theObject.length; i++) {
            result = getObject(theObject[i], i);
            if (result) {
                break;
            }   
        }
    }
    else
    {
        for(var prop in theObject) {
            if(prop == 'iframe' && theObject[prop]) {
                i--;
                console.log('iframe', theObject[prop])
                return theObject[prop]
            }
            if(theObject[prop] instanceof Object || theObject[prop] instanceof Array) {
                result = getObject(theObject[prop], prop);
                if (result) {
                    break;
                }
            } 
        }
    }
    if (result) console.info(k)
    return result;
}

Выполнение следующего: getObject(reader, 'reader') дал следующий вывод и iframe элемент в конце:

iframe // (The Dom Element)
_views
views
manager
rendition
book
reader

ПРИМЕЧАНИЕ: путь в обратном порядке reader.book.rendition.manager.views._views.iframe

1
ответ дан 1 November 2019 в 14:21

Я хотел бы предложить поправку к ответу Zach/RegularMike (но не имейте "репутации", чтобы смочь прокомментировать!). Я нашел там решение очень полезным основанием, но пострадал в моем приложении, потому что, если бы существуют строки в массивах, оно рекурсивно вызвало бы функцию для каждого символ в строке (который вызвал IE11 & Граничные браузеры для сбоя с "из стекового пространства" ошибки). Моя простая оптимизация должна была добавить тот же тест, используемый в "объектном" рекурсивном вызове пункта того в пункте "массива":

if (arrayElem instanceof Object || arrayElem instanceof Array) {

Таким образом мой полный код (который теперь ищет все экземпляры конкретного ключа, настолько немного отличающегося к исходному требованию):

// Get all instances of specified property deep within supplied object
function getPropsInObject(theObject, targetProp) {
    var result = [];
    if (theObject instanceof Array) {
        for (var i = 0; i < theObject.length; i++) {
            var arrayElem = theObject[i];
            if (arrayElem instanceof Object || arrayElem instanceof Array) {
                result = result.concat(getPropsInObject(arrayElem, targetProp));
            }
        }
    } else {
        for (var prop in theObject) {
            var objProp = theObject[prop];
            if (prop == targetProp) {
                return theObject[prop];
            }
            if (objProp instanceof Object || objProp instanceof Array) {
                result = result.concat(getPropsInObject(objProp, targetProp));
            }
        }
    }
    return result;
}
1
ответ дан 1 November 2019 в 14:21

Я попытался бы не изобрести велосипед. Мы используем объектное сканирование для всех наших потребностей обработки данных. Это концептуально очень просто, но допускает много интересного материала. Вот то, как Вы решили бы свой конкретный вопрос

Определение данных

const data = [{
  'title': "some title",
  'channel_id': '123we',
  'options': [{
    'channel_id': 'abc',
    'image': 'http://asdasd.com/all-inclusive-block-img.jpg',
    'title': 'All-Inclusive',
    'options': [{
      'channel_id': 'dsa2',
      'title': 'Some Recommends',
      'options': [{
        'image': 'http://www.asdasd.com',
        'title': 'Sandals',
        'id': '1',
        'content': {}
      }]
    }]
  }]
}];

Логика

const objectScan = require('object-scan');

const scanner = (input) => {
  let obj = null;
  objectScan(['**.id'], {
    filterFn: (key, value, { parents }) => {
      if (value === '1') {
        obj = parents[0];
      }
    },
    breakFn: () => obj !== null
  })(data);
  return obj;
};

const result = scanner(data);

Вывод

// result =>
{
  "image": "http://www.asdasd.com",
  "title": "Sandals",
  "id": "1",
  "content": {}
}
0
ответ дан 1 November 2019 в 14:21

Другие вопросы по тегам:

Похожие вопросы: