通过数组循环遍历对象树

时间:2019-07-10 13:08:32

标签: javascript arrays object for-loop

我有一个问题,要根据给定的数组对象动态向下移动对象。

尝试了一些静态代码,但这在存在更多或更少级别的情况下不灵活

// value = 10
// field = ["data", "input", "level", "0"]
item[field[0]][field[1]][field[2]][field[3]] = value

我不知道从哪里开始使用for循环执行此功能。有人可以给我一些建议开始吗?

6 个答案:

答案 0 :(得分:2)

您可以缩小字段并获取一个对象及其属性。最后,用最后一个键分配值。

const
    setValue = (object, [...path], value) => {
        var last = path.pop();
        path.reduce((o, k) => o[k] = o[k] || {}, object)[last] = value;
    },
    object = {},
    value = 10,
    fields = ["data", "input", "level", "0"];
    
setValue(object, fields, value);

console.log(object);

答案 1 :(得分:1)

Lodash上有一个内置方法可以执行此操作-how to load their tools asynchronously

_.set(item, field, value)

let item = {
  data: {
    input: {
      level: [5]
    }
  }
};

const field = ["data", "input", "level", "0"];
const value = 10;

_.set(item, field, value);

console.log(item);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.js"></script>

答案 2 :(得分:0)

您可以保留一个current变量,该变量代表对象中当前所在的对象,然后在循环完成后在最后设置值:

const item = {
  "data": {
    "input": {
      "level": {
        0: -1
      }
    }
  }
}

let value = 10;
let field = ["data", "input", "level", "0"];
let current = item[field[0]];
for (let i = 1; i < field.length - 1; i++) {
  current = current[field[i]];
}
current[field.pop()] = value;
console.log(item);

上述操作也可以递归实现(如果存在伪造的字段值,请使用nf === undefined而不是!nf

const item = {
  "data": {
    "input": {
      "level": {
        0: -1
      }
    }
  }
}


let value = 10;
let field = ["data", "input", "level", "0"];

const set_val = (val, obj, [f, nf, ...rest]) =>
	!nf ? obj[f] = val : set_val(val, obj[f], [nf, ...rest]);

set_val(value, item, field);
console.log(item);

如果您希望从头开始构建item对象,也可以这样做:

const value = 10;
const field = ["data", "input", "level", "0"];
let item = {};
let curr = item;
for (let i = 0; i < field.length - 1; i++) {
  curr[field[i]] = {}; 
  curr = curr[field[i]];
}

curr[field.pop()] = value;
console.log(item);

此构建也可以像这样递归完成:

const value = 10;
const field = ["data", "input", "level", "0"];
let item = {};
let curr = item;
const set_val = (val, [f, nf, ...rest], item = {}) => {
  if (!nf) {
    item[f] = val;
    return item;
  } else {
    item[f] = set_val(val, [nf, ...rest], item[f]);
    return item;
  }
}

console.log(set_val(value, field));

答案 3 :(得分:0)

您可以使用递归函数浏览对象:

var value = 10;
var field = ["data", "input", "level", "0"];

var obj =
{
  data: 
  {
      input:
      {
        level: [42]
      }
  }
};

function SetValue(field, obj, value, index = 0)
{
  var memberName = field[index];
  // not at last item ?
  if (index < field.length - 1)
  {
    
    if (obj.hasOwnProperty(memberName))
    {
      SetValue(field, obj[memberName], value, index + 1);
    }
  }
  else
  {
    obj[memberName] = value;
  }
}
console.log("Before");
console.log(obj);
console.log("---------------------");
SetValue(field, obj, value);
console.log("After");
console.log(obj);
console.log("---------------------");

答案 4 :(得分:0)

我已经在生产环境中使用了一个函数,该函数实际上可以实现您想要的:

/**
 * Replace an item in datasource with specified path with new value.  
 * Will _create_ an item if the path does not currently exist.
 * @param {object} o Datasource
 * @param {array} k Array of keys used to access item (usually getPath())
 * @param {*} v New value of specified item
 */
const replaceItem = (o, k, v) => k.reduce((r, e, i, a) => {
  if (!a[i + 1]) r[e] = v;
  else return r[e]
}, o)

const dataSource = {
  data: {
    input: {
      level: [1]
    }
  }
}

const path = ["data", "input", "level", "0"]
replaceItem(dataSource, path, 5)
console.log(dataSource)

答案 5 :(得分:0)

另一种版本,略有不同。它区分创建的对象是Object还是Array

const setValue = (object, path, value) => {
  if (!object || !path || !path.length) return;

  var key = path[0],
    i = 1,
    prev = key;

  while (i < path.length) {
    key = path[i++];
    object = object[prev] || (object[prev] = +key === (key >>> 0) ? [] : {});
    prev = key;
  }

  object[key] = value;
};

const object = {};
setValue(object, ["data", "input", "level", "0"], 10);
console.log(object);