Цикл по дереву объектов по массиву - PullRequest
3 голосов
/ 10 июля 2019

У меня есть вопрос о динамическом переходе по объекту по заданному объекту массива.

Пробовал с некоторым статическим кодом, но это не гибко в ситуации, когда есть более или менее уровни

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

Я понятия не имею, с чего начать с функции, выполняющей это с циклом for. Кто-нибудь может дать мне несколько советов, чтобы начать.

Ответы [ 6 ]

2 голосов
/ 10 июля 2019

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

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 голос
/ 10 июля 2019

В Lodash есть встроенный метод, который делает именно это - _.set.

_.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>
0 голосов
/ 10 июля 2019

другая версия, с изюминкой.Он различает, должен ли создаваемый объект быть 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);
0 голосов
/ 10 июля 2019

Я уже использую в производстве функцию, которая буквально делает то, что вы хотите:

/**
 * 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)
0 голосов
/ 10 июля 2019

Вы можете использовать рекурсивную функцию для навигации по вашему объекту:

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("---------------------");
0 голосов
/ 10 июля 2019

Вы можете сохранить переменную 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));
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...