Object.assign-override вложенное свойство

У меня есть объект a вроде этого:

const a = {
  user: {
   …
   groups: […]
   …
  }
}

в результате чего в a.user

имеется намного больше свойств,

И я хотел бы изменить только значение a.user.groups. Если я это сделаю:

const b = Object.assign({}, a, {
  user: {
    groups: {}
  }
});

b не имеет другого свойства кроме b.user.groups, все остальные удаляются. Есть ли способ ES6 только изменить вложенное свойство, не теряя всего другого, с помощью Object.assign?

Ответ 1

После некоторых попыток я смог найти решение, которое выглядит довольно красиво:

const b = Object.assign({}, a, {
  user: {
    ...a.user,
    groups: 'some changed value'
  }
});

Чтобы сделать этот ответ более полным, крошечное примечание:

const b = Object.assign({}, a)

по существу совпадает с:

const b = { ...a }

поскольку он просто копирует все свойства a (...a) в новый объект. Таким образом, вышесказанное может быть написано как:

 const b = {
   ...a,          //copy everything from a
   user: {        //override the user property
      ...a.user,  //same sane: copy the everything from a.user
      groups: 'some changes value'  //override a.user.group
   }
 }

Ответ 2

Вы можете изменить его таким образом,

const b = Object.assign({}, a, {
  user: Object.assign({}, a.user, {
          groups: {}
        })
});

или просто сделайте,

const b = Object.assign({}, a);
b.user.groups = {};

Ответ 3

Метод Object.assign() используется для копирования значений всех перечислимых собственных свойств из одного или нескольких исходных объектов в целевой объект. Он вернет целевой объект.

метод присваивания сделает новый объект путем копирования из исходного объекта, проблема, если вы измените какой-либо метод позже в исходном объекте, он не будет отражен в новом объекте.

Используйте create()

Метод Object.create() создает новый объект с указанным объектом и свойствами прототипа.

const b = Object.create(a)
b.user.groups = {}
// if you don't want the prototype link add this
// b.prototype = Object.prototype 

Таким образом, вы связаны с прототипом b, и если вы внесете какие-либо изменения в a, это будет отражено в b, и любые изменения в b не повлияют на

Ответ 4

Вы спросили, в частности, о ES6 с Object.assign, но, возможно, кто-то предпочтет мой более "общий" ответ - вы можете сделать это легко с lodash, и лично я считаю, что это решение более читаемо.

import * as _ from 'lodash';
_.set(a, 'user.groups', newGroupsValue);

Он мутирует объект.

Ответ 5

Маленькая точная мелодия Филлипса первый ответ.

const object1 = {
  abc: {
    a: 1
  }
};

const object2 = {
  abc: {
    b: 2
  }
};

Object.assign(object1, {
    abc: {
        ...object1.abc,
        ...object2.abc
    }
});

console.log(object1);
// Object { abc: Object { a: 1, b: 2 } }

Ответ 6

Здесь небольшая функция под названием Object_assign (просто замените . на _, если вам нужно вложенное присваивание)

Функция устанавливает все целевые значения, либо вставляя туда исходное значение напрямую, либо рекурсивно вызывая Object_assign снова, когда и целевое значение, и исходное значение являются объектами non- null.

const target = {
  a: { x: 0 },
  b: { y: { m: 0, n: 1      } },
  c: { z: { i: 0, j: 1      } },
  d: null
}

const source1 = {
  a: {},
  b: { y: {       n: 0      } },
  e: null
}

const source2 = {
  c: { z: {            k: 2 } },
  d: {}
}

function Object_assign (target, ...sources) {
  sources.forEach(source => {
    Object.keys(source).forEach(key => {
      const s_val = source[key]
      const t_val = target[key]
      target[key] = t_val && s_val && typeof t_val === 'object' && typeof s_val === 'object'
                  ? Object_assign(t_val, s_val)
                  : s_val
    })
  })
  return target
}

console.log(Object_assign(Object.create(target), source1, source2))

Ответ 7

Более общее решение ниже. Это делает рекурсивное назначение, только если есть конфликты (те же имена ключей). Это решает проблемы назначения сложных объектов, которые имеют много опорных точек. Например, nested-object-assign, существующий пакет для присвоения вложенных объектов в npm, застрял с назначением сложных объектов, потому что он рекурсивно проходит через все ключи.

var objecttarget = {
  a: 'somestring',
  b: {x:2,y:{k:1,l:1},z:{j:3,l:4}},
  c: false
};

var objectsource = {
  a: 'somestring else',
  b: {k:1,x:2,y:{k:2,p:1},z:{}},
  c: true
};

function nestedassign(target, source) {
  Object.keys(source).forEach(sourcekey=>{
    if (Object.keys(source).find(targetkey=>targetkey===sourcekey) !== undefined && typeof source[sourcekey] === "object") {
      target[sourcekey]=nestedassign(target[sourcekey],source[sourcekey]);
    } else {
      target[sourcekey]=source[sourcekey];
    }
  });
  return target;
}

// It will lose objecttarget.b.y.l and objecttarget.b.z
console.log(Object.assign(Object.create(objecttarget),objectsource));

// Improved object assign
console.log(nestedassign(Object.create(objecttarget),objectsource));