У меня есть объект a такой:

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

Благодаря чему в a.user есть намного больше свойств

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

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

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

69
philipp 11 Янв 2017 в 13:15

7 ответов

Лучший ответ

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

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
   }
 }
88
philipp 21 Фев 2018 в 06:56

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

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 } }
1
Ballpin 20 Ноя 2018 в 08:13

Вы можете изменить это так,

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

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

const b = Object.assign({}, a);
b.user.groups = {};
6
pratZ 11 Янв 2017 в 10:31

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

Функция устанавливает все целевые значения, либо вставляя туда исходное значение напрямую, либо рекурсивно вызывая Object_assign, когда и целевое, и исходное значение не являются объектами 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))
3
Gust van de Wal 24 Сен 2019 в 23:42

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

Метод 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 через прототип, и если вы сделаете какие-либо изменения в a, это будет отражено в b, и любые изменения в b не повлияют на a

4
Abdullah Alsigar 11 Янв 2017 в 12:09

Более общее решение ниже. Это делает рекурсивное назначение, только если есть конфликты (одинаковые имена ключей). Это решает проблемы назначения сложных объектов, которые имеют много опорных точек. Например, 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));
-1
Minime 24 Май 2019 в 14:48

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

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

Это мутирует объект.

4
Patryk Wlaź 18 Май 2017 в 09:11