访问多级属性及其完整的属性路径

时间:2017-08-01 15:26:07

标签: javascript object data-manipulation accessor

我目前正在努力解决JavaScript问题。我希望通过传入原始对象以及指向我想要的属性的路径数组来返回多级属性以及其中包含的每个变量。

例如,如果我有以下对象:

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>JS Bin</title>
   <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
</head>
<body>
<script>
$(function(){
    $(document).on("test", function(){
        alert("test triggered");
    });
    $(document).trigger("test");
});
</script> 
</body>
</html>

我希望能够调用方法:

obj = {
  product: {
    candidate: {
      id: 10,
      reference: "test",
      count: 4,
      steps: 10
    }
  }
}

然后让它返回一个对象,其中每个变量都在数组中传递,在它的原始结构中。所以这将返回一个看起来像这样的对象:

getVarPath(obj, ["product.candidate.ID", "product.candidate.reference"])

我现在在本地解决方案中使用此功能(此时传入一个字符串而不是数组)。

目前的解决方案非常可怕但我希望改进它,所以如果有人能想到一个更好的方法。 再说一次,这是非常可怕的,但我正在寻求改进它。但它完成了这项工作:

{
  product: {
    candidate: {
      id: 10,
      reference: "test"
    }
  }
}

3 个答案:

答案 0 :(得分:0)

对于输入数组中的每个元素:

首先,您可以拆分初始字符串:var nestedElements="product.candidate.ID".split(.)"
这将返回每个级别的数组:["product","candidate","ID"]

现在,您可以使用数组的每个元素访问嵌套对象:obj["product"]["candidate"]["ID"],方法是使用数组循环或递归。

var currentobj=obj;
for (var i=0;i<nestedElements.length;i++){
  currentobj=currentobj[nestedElements[i]]
}
// currentobj is your id      

在同一过程中,您可以使用类似的过程动态地向新的obj添加元素:

newobj={} //before loop
if (newobj["product"] === undefined) newobj["product"]={} //in loop

这应该对输入数组中的每个元素进行,最后是遍历数组并使用字符串访问对象

答案 1 :(得分:0)

您的代码原样不应该真正起作用。您将keys视为字符串,但传入数组。您可以(并且应该)避免使用eval(),跟踪您当前正在查看的“内部”对象,并使用object[property]表示法而不是object.property

function getVarPath(obj, keys) {
  var result = {};

  // ["product.candidate.id", "product.candidate.reference"]
  keys.forEach(function(key) {
    var src = obj,     // inner source object
        dest = result, // inner destination object
        parts = key.split(/\./);

    // e.g. ["product", "candidate", "id"]
    parts.forEach(function(part) {

      // if we're looking at an object, make sure it exists in the dest
      if (typeof(src[part]) === "object")
        dest[part] = dest[part] || {};
      // if it's just a value, copy it  
      else
        dest[part] = src[part];

      dest = dest[part]; // move from obj to obj.product, then to obj.product.candidate, etc.
      src = src[part];
    });
  });

  return result;
}

var obj = {
  product: {
    candidate: {
      id: 10,
      reference: "test",
      count: 4,
      steps: 10
    }
  }
}

var output = getVarPath(obj, ["product.candidate.id", "product.candidate.reference"]);

console.log(JSON.stringify(output));

答案 2 :(得分:0)

使用_.propertyOf()Array#reduce()Object.assign()以及computed property names,您可以创建一个不那么令人生畏的实现:

&#13;
&#13;
function getVarPath(object, paths) {
  return paths.reduce(function (accumulator, path) {
    const that = _.propertyOf(accumulator)
    let walk = path.split('.')
    let value = this(walk)

    for (let key = walk.pop(); key !== undefined; key = walk.pop()) {
      const base = that(walk)

      value = { [key]: value }

      if (base !== undefined) {
        value = Object.assign(base, value)
      }
    }

    return Object.assign(accumulator, value)
  }.bind(_.propertyOf(object)), {})
}

let obj = {
  product: {
    candidate: {
      id: 10,
      reference: "test",
      count: 4,
      steps: 10
    }
  }
}

console.log(getVarPath(obj, ['product.candidate.id', 'product.candidate.reference']))
&#13;
<script src="https://cdn.rawgit.com/lodash/lodash/4.17.4/dist/lodash.min.js"></script>
&#13;
&#13;
&#13;