为大型嵌套对象实现对象迭代器的问题

时间:2019-03-09 02:15:07

标签: javascript

想象一下有一个对象,我们正在尝试编写一个函数,该函数将'path'用作余量并打印其中的任何内容。如果输入无效,则引发错误。对象大小可能很大。

const obj = {
  test: {
    demo: [{
      lname: 'dave'
    }]
  }
};

function getData(obj, dest) {
  const path = dest.split('.');
  return helper(obj, path);

  function helper(obj, path) {
    if (!path.length) return obj;
    const cur = path.shift();

    if ((Array.isArray(obj) && typeof obj === 'string') ||
      (typeof obj === 'undefined')) {
      throw new Error("Something wrong")
    }

    obj = obj[cur];
    return helper(obj, path);
  }
}

console.log(getData(obj, 'test.demo.0.lname'));
//console.log(getData(obj, 'test.demo.dave.lname')); // throws an error since in demo array you can't access 'dave'

我正在尝试找出编写此方法的较短方法是什么?我听说有人说我们可以写几行。

1 个答案:

答案 0 :(得分:1)

一个简单快捷的实现可以使用Array#reduce来迭代地从对象上取下键,如下所示:

const obj = {
  test: {
    demo: [{
      lname: 'dave'
    }]
  }
};

function getData(obj, dest) {
  var keys = dest.split(".");
  return keys.reduce(function(currentObject, key) {
    if(typeof currentObject == "undefined") throw Error("Something wrong");
    return currentObject[key];
  }, obj)
}

console.log(getData(obj, 'test.demo.0.lname'));
console.log(getData(obj, 'test.demo.dave.lname')); // throws an error since in demo array you can't access 'dave'

这是更冗长的选项,为了演示正在发生的事情,您可以进一步缩短它

const obj = {
  test: {
    demo: [{
      lname: 'dave'
    }]
  }
};

function getData(obj, dest) {
  return dest.split(".").reduce((curr, key) => curr[key], obj)
}

console.log(getData(obj, 'test.demo.0.lname'));
console.log(getData(obj, 'test.demo.dave.lname')); // throws an error since in demo array you can't access 'dave'

您还可以避免引发错误,但是如果找不到密钥,只需返回undefined

const obj = {
  test: {
    demo: [{
      lname: 'dave'
    }]
  }
};

function getData(obj, dest) {
  return dest.split(".").reduce((curr, key) => curr != undefined ? curr[key] : undefined, obj)
}

console.log(getData(obj, 'test.demo.0.lname'));
console.log(getData(obj, 'test.demo.dave.lname')); // undefined

但是,尽管这很容易实现,但要以错误检查为代价。调试到底出了什么问题可能会很烦人,因为您必须知道数据对象和目标输入是什么,然后尝试找出手动缺少的键。因此,如果您想要更健壮和灵活的代码,则更长的实现通常会更好。

如果您使用的是Lodash,则可以使用其_.get,它更加健壮并可以处理更多语法

const obj = {
  test: {
    demo: [{
      lname: 'dave'
    }]
  }
};

console.log(_.get(obj, 'test.demo.0.lname'));
console.log(_.get(obj, 'test.demo[0].lname'));
console.log(_.get(obj, ['test', 'demo', 0, 'lname']));

console.log(_.get(obj, 'test.demo.dave.lname')); // undefined

console.log(_.get(obj, 'test.demo.dave.lname', 'this is not dave but the default vale'));
<script src="https://cdn.jsdelivr.net/npm/lodash@4.17.11/lodash.min.js"></script>