在深层嵌套的对象数组中搜索单个键

时间:2018-08-23 16:37:50

标签: javascript traversal

我正在尝试搜索一个深层嵌套的数组,以查找内部是否有键。我已经编写了一段遍历的代码,但是由于它不是递归的(仅自我调用),因此无法返回是否找到了任何东西。它只返回undefined,因为它在一次传递中到达了函数的末尾。

我想知道是否有一种方法可以使我在第一次出现特定键时返回true

这是到目前为止我一直在使用的JS bin:

https://jsbin.com/qaxuwajuso/edit?js,console

这是上面示例中代码的直接粘贴:

function traverse(item, key) {
    if (typeof item === 'object' && !Array.isArray(item) && item !== null) {
        // Object
        for (let itemKey in item) {
            if (itemKey === key) {
                // Is it possible to return true and break out of the function here?
                console.log('found the key: ' + itemKey + ' With value: ' + item[itemKey]);
            }

            traverse(item[itemKey], key);
        }
    } else if (Array.isArray(item)) {
        // Array
        for (let i = 0; i < item.length; ++i) {
            traverse(item[i], key);
        }
    }
}

任何帮助将不胜感激。谢谢您的时间!

3 个答案:

答案 0 :(得分:2)

确定只需要返回某种标志来触发循环停止

/*
 * I am trying to search the following json array for any occurance of the key "statePath".
 * In a perfect world I would be able to find the first occurance, and return true from the
 * function.
 *
 * The following data is not real, I was just trying to write as much nested stuff as possible
 * to test that it traverses as far as needed.
 */

const data = [
    {
        id: '2144d998-4c33-4b03-93d2-f6c675b24508',
        element: 'div',
        props: {
            className: 'testing',
            name: [
                {
                    first: 'John',
                    last: {
                        statePath: 'lastName',
                        anArray: [
                          {
                            anObject: {
                              anotherArray: [
                                {
                                  doesItWork: {
                                    statePath: 'hello',
                                  },
                                },
                              ],
                            },
                          },
                        ],
                    },
                },
                {
                    first: 'Jane',
                    last: {
                        statePath: 'lastName',
                    },
                },
            ],
        },
        children: 'hi',
    },
];

function traverse(item, key) {
  if (typeof item === 'object' && !Array.isArray(item) && item !== null) {
    // Object
    for (let itemKey in item) {
      if (itemKey === key) {
        console.log('found the key: ' + itemKey + ' With value: ' + item[itemKey]);
        
        // not sure what you want the end "return" of the func to be, I'm returning the value.  You could return true here instead, you could return a reference to the parent object, lots of possibilities
        return item[itemKey];
      }
      var found = traverse(item[itemKey], key);
      if (found !== undefined) return found;
      // otherwise keep looking
    }
  } else if (Array.isArray(item)) {
    // Array
    for (let i = 0; i < item.length; ++i) {
      var found = traverse(item[i], key);
      if (found !== undefined) return found;
    }
  }
}

var value = traverse(data, 'statePath');
console.log("value is " + value);

答案 1 :(得分:1)

您可以使用for...in并将结果存储在一个var中,然后在再次调用函数之前检查该var,如果找到值则中断循环。

const data = [{"id":"2144d998-4c33-4b03-93d2-f6c675b24508","statePath":"div","props":{"className":"testing","name":[{"first":"John","last":{"statePath":"lastName","anArray":[{"anObject":{"anotherArray":[{"doesItWork":{"statePath":"hello"}}]}}]}},{"first":"Jane","last":{"statePath":"lastName"}}]},"children":"hi"}]

function traverse(item, key) {
  let result = false;

  for (var i in item) {
    if (i == key) {
      result = true;
      break;
    }
    if (typeof item[i] == 'object' && !result) {
      result = traverse(item[i], key)
    }
  }

  return result
}

console.log(traverse(data, 'statePath'))

答案 2 :(得分:0)

我的变体:

const data = [{id: '2144d998-4c33-4b03-93d2-f6c675b24508', element: 'div', props: {className: 'testing', name: [{first: 'John', last: {statePath3: 'lastName', anArray: [{anObject: {anotherArray: [{doesItWork: {statePath1: 'hello',},},],},},],},}, {first: 'Jane', last: {statePath: 'lastName',},},],}, children: 'hi',},];

function traverse(data, find) {
  for (let k in data) {
    let deepHaveKey = typeof data[k] === 'object' && traverse(data[k], find)
    
    if (find === k || deepHaveKey)
      return true
  }
  
  return false
}

console.log(traverse(data, 'statePath')); // true
console.log(traverse(data, 'state')); // false