Как я могу клонировать объект JavaScript, кроме одного ключа?


308

У меня есть плоский объект JS:

{a: 1, b: 2, c: 3, ..., z:26}

Я хочу клонировать объект, за исключением одного элемента:

{a: 1, c: 3, ..., z:26}

Какой самый простой способ сделать это (предпочитая использовать es6 / 7, если это возможно)?


Без изменения исходного объекта: JSON.parse (JSON.stringify ({... obj, 'key2': undefined}))
infinity1975

Ответы:


441

Если вы используете Babel, вы можете использовать следующий синтаксис, чтобы скопировать свойство b из x в переменную b, а затем скопировать остальные свойства в переменную y :

let x = {a: 1, b: 2, c: 3, z:26};
let {b, ...y} = x;

и он будет перенесен в:

"use strict";

function _objectWithoutProperties(obj, keys) {
  var target = {};
  for (var i in obj) {
    if (keys.indexOf(i) >= 0) continue;
    if (!Object.prototype.hasOwnProperty.call(obj, i)) continue;
    target[i] = obj[i];
  }
  return target;
}

var x = { a: 1, b: 2, c: 3, z: 26 };
var b = x.b;

var y = _objectWithoutProperties(x, ["b"]);

58
Если вы поменяете свой код на неиспользуемые переменные, это приведет к «Неиспользуемой переменной« b »». предупреждение хотя.
Росс Аллен

1
как бы выглядел синтаксис, если бы вы имелиlet x = [{a: 1, b: 2, c: 3, z:26}, {a: 5, b: 6, c: 7, z:455}];
ke3pup

14
@RossAllen В версии 3.15.0 ignoreRestSiblingsбыла добавлена ​​опция (3 февраля 2017 г.). Смотрите: commit c59a0ba
Илья Палкин

4
@IlyaPalkin Интересно. Это кажется немного ленивым, хотя, потому что это не меняет факт, что есть bв области.
Росс Аллен

2
Если вы получаете сборку модуля не удалась: SyntaxError: Неожиданный токен, вам, вероятно, необходимо добавить плагин преобразования преобразования оставшейся части Babel. См. Babeljs.io/docs/plugins/transform-object-rest-spread
jsaven

133
var clone = Object.assign({}, {a: 1, b: 2, c: 3});
delete clone.b;

или если вы принимаете свойство неопределенным:

var clone = Object.assign({}, {a: 1, b: 2, c: 3}, {b: undefined});

7
Простое удаление свойства - это простой и понятный способ сделать это.
шоу

24
Предостережение с удалением состоит в том, что это не неизменная операция.
Джавид Джаме

1
это держит ключ
Фарид Алнамрути

1
Мой комментарий был написан до того, как он отредактировал свой ответ и добавил заявление об удалении
Фарид Алнамрути

Это именно то, что я искал, но немного более реализовано немного другим способом: var cake = {... currentCake, requestorId: undefined};
abelito

73

Чтобы добавить к ответу Ильи Палкина: вы можете даже динамически удалять ключи:

const x = {a: 1, b: 2, c: 3, z:26};

const objectWithoutKey = (object, key) => {
  const {[key]: deletedKey, ...otherKeys} = object;
  return otherKeys;
}

console.log(objectWithoutKey(x, 'b')); // {a: 1, c: 3, z:26}
console.log(x); // {a: 1, b: 2, c: 3, z:26};

Демо в Babel REPL

Источник:


3
Это хороший синтаксис.
Хинрих

2
Это здорово, но есть ли способ избежать неиспользуемой переменной var selectedKey? Не то, чтобы это вызывало какие-либо проблемы, но заставляет JSHint жаловаться, и это кажется странным, поскольку мы действительно его не используем
Джонсон Вонг

6
@JohnsonWong Как насчет использования _которого разрешено для переменной, которую вы не собираетесь использовать?
Райан Х.

var b = {a:44, b:7, c:1}; let {['a']:z, ...others} = b; console.log(z , others ); // logs: 44, {b:7, c:1}
Джиммонт

70

Для тех, кто не может использовать ES6, вы можете использовать lodashили underscore.

_.omit(x, 'b')

Или ramda.

R.omit('b', x)

6
не будет ли более логичным использовать здесь опускать ? _.omit(x, 'b')
Тибальт

Спасибо @tibalt. Обновил ответ вместе с ним.
Ноэль Льеварес

удаление является более кратким - использование lodash, underscore или ramda относится только к проектам, которые уже используют и знают их, в противном случае это становится все более неактуальным в 2018 году и в последующий период.
Джиммонт

1
@jimmont delete уже упоминался в других ответах. Не нужно повторять ответы, не правда ли? И конечно, это актуально только для тех, кто уже использует lodash или ramda. И это также относится только к тем, кто застрял с ES5 и ранее, как указано в этом ответе.
Ноэль Льеварес

@dashmug Мой предыдущий комментарий был критикой подхода (не вашего ответа), который следует отметить при выборе использования подхода, представленного в этом ответе. Я хотел бы получить эту информацию, если бы я читал ответы, и это является причиной для добавления моего комментария и упоминания delete.
Джиммонт

63

Я использую этот лайнер ESNext

const obj = { a: 1, b: 2, c: 3, d: 4 }
const clone = (({ b, c, ...o }) => o)(obj) // remove b and c
console.log(clone)


Если вам нужна функция общего назначения:

function omit(obj, props) {
  props = props instanceof Array ? props : [props]
  return eval(`(({${props.join(',')}, ...o}) => o)(obj)`)
}

// usage
const obj = { a: 1, b: 2, c: 3, d: 4 }
const clone = omit(obj, ['b', 'c'])
console.log(clone)


9
Вместо обёртывания в массив и mapвы можете сделать:(({b, c, ...others}) => ({...others}))(obj)
bucabay

@bucabay: Отлично! Это лучший ответ из всех! Соответствие стандартам, отлично работает в Node и т. Д. Вы должны представить в качестве ответа.
david.pfx

3
Фантастический ответ приятель .. <3
Ajithkumar S

5
@totymedli: Не мной. Я приму синтаксическую форму, часть стандартного ES6, над магической функцией в любое время на основе читабельности.
david.pfx

1
Brilliant. Вот и все.
darksoulsong

22

Вы можете написать простую вспомогательную функцию для него. У Lodash есть похожая функция с тем же именем: omit

function omit(obj, omitKey) {
  return Object.keys(obj).reduce((result, key) => {
    if(key !== omitKey) {
       result[key] = obj[key];
    }
    return result;
  }, {});
}

omit({a: 1, b: 2, c: 3}, 'c')  // {a: 1, b: 2}

Кроме того, обратите внимание, что это быстрее, чем Object.assign и затем удалите: http://jsperf.com/omit-key


11

Может быть, что-то вроде этого:

var copy = Object.assign({}, {a: 1, b: 2, c: 3})
delete copy.c;

Это достаточно хорошо? Или на cсамом деле не может быть скопировано?


11

Использование уничтожения объектов

const omit = (prop, { [prop]: _, ...rest }) => rest;
const obj = { a: 1, b: 2, c: 3 };
const objWithoutA = omit('a', obj);
console.log(objWithoutA); // {b: 2, c: 3}


Отличное решение!
Денис Михаленко

2
Я предполагаю, что это решение предназначено для предотвращения предупреждения «Неиспользуемая переменная» в JSLint. К сожалению, использование _не решает проблему для ESLint ...
Bert Bruynooghe

6

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

Простой трюк (может быть ужасно), я использовал это

var obj = {"key1":"value1","key2":"value2","key3":"value3"};

// assign it as a new variable for javascript to cache
var copy = JSON.stringify(obj);
// reconstitute as an object
copy = JSON.parse(copy);
// now you can safely run delete on the copy with completely new values
delete copy.key2

console.log(obj)
// output: {key1: "value1", key2: "value2", key3: "value3"}
console.log(copy)
// output: {key1: "value1", key3: "value3"}

На самом деле мне это нравится. Мог сделать JSON.parse(JSON.stringify(Object.assign({}, obj, { key2: undefined })));. Не нужно даже удалять его, просто нужно ложное значение.
Чад

6

Вот вариант для пропуска динамических ключей, который, я считаю, еще не был упомянут:

const obj = { 1: 1, 2: 2, 3: 3, 4: 4 };
const removeMe = 1;

const { [removeMe]: removedKey, ...newObj } = obj;

removeMeпсевдоним removedKeyи игнорируется. newObjстановится { 2: 2, 3: 3, 4: 4 }. Обратите внимание, что удаленный ключ не существует, значение не было просто установлено undefined.


Хорошее решение. У меня был похожий вариант использования (динамический ключ в редукторе).
Эричио

4

САМЫЙ ПРОСТОЙ СПОСОБ

const allAlphabets = {a: 1, b: 2, c: 3, ..., z:26};
const { b, ...allExceptOne } = allAlphabets;
console.log(allExceptOne);   // {a: 1, c: 3, ..., z:26}

3

Lodash опустить

let source = //{a: 1, b: 2, c: 3, ..., z:26}
let copySansProperty = _.omit(source, 'b');
// {a: 1, c: 3, ..., z:26}

да, Lodash - элегантный вариант, но я пытался добиться того же с ванильной ES6
andreasonny83

3

Вы также можете использовать оператор спреда, чтобы сделать это

const source = { a: 1, b: 2, c: 3, z: 26 }
const copy = { ...source, ...{ b: undefined } } // { a: 1, c: 3, z: 26 }

2
Кажется, супер изящный. Это, однако, сохраняет ключ как неопределенный вcopy
kano

так что вы можете удалить неопределенные ключи, если там есть только одни
Виктор

1
Не уверен, почему вы сделали дополнительное распространение в копии, const copy = { ...source, b: undefined } сводится к точно так же.
Берт Брюнооге

3

Решения, описанные выше с использованием структурирования, страдают от того, что у вас есть используемая переменная, которая может вызвать жалобы от ESLint, если вы ее используете.

Итак, вот мои решения:

const src = { a: 1, b: 2 }
const result = Object.keys(src)
  .reduce((acc, k) => k === 'b' ? acc : { ...acc, [k]: src[k] }, {})

На большинстве платформ (кроме IE, если не используется Babel), вы также можете сделать:

const src = { a: 1, b: 2 }
const result = Object.fromEntries(
  Object.entries(src).filter(k => k !== 'b'))


2

Если вы имеете дело с огромной переменной, вы не хотите копировать ее, а затем удалять, поскольку это будет неэффективно.

Должен работать простой цикл for с проверкой hasOwnProperty, и он гораздо более адаптируем к будущим потребностям:

for(var key in someObject) {
        if(someObject.hasOwnProperty(key) && key != 'undesiredkey') {
                copyOfObject[key] = someObject[key];
        }
}

1
Решение с оператором распространения делает то же самое с гораздо более приятным синтаксисом.
david.pfx

2

Как насчет этого? Я никогда не встречал этот шаблон, но я просто пытался исключить одно или несколько свойств без необходимости создания дополнительного объекта. Это, кажется, делает работу, но есть некоторые побочные эффекты, которые я не могу видеть. Наверняка не очень читабельно.

const postData = {
   token: 'secret-token',
   publicKey: 'public is safe',
   somethingElse: true,
};

const a = {
   ...(({token, ...rest} = postData) => (rest))(),
}

/**
a: {
   publicKey: 'public is safe',
   somethingElse: true,
}
*/

2

Я сделал это таким образом, как пример из моего редуктора Redux:

 const clone = { ...state };
 delete clone[action.id];
 return clone;

Другими словами:

const clone = { ...originalObject } // note: original object is not altered
delete clone[unwantedKey]           // or use clone.unwantedKey or any other applicable syntax
return clone                        // the original object without the unwanted key

Похоже, много дополнительной работы, по сравнению с принятым ответом от 3 лет назад (и оба варианта полагаются на использование во многих браузерах).
carpiediem

У меня есть похожий вариант использования (редуктор), поэтому я нашел хороший способ, который поддерживает динамические ключи без мутаций. В основном: const { [removeMe]: removedKey, ...newObj } = obj;- см. Мой ответ на этот вопрос.
Goldins

1

Я недавно сделал это очень простым способом:

const obj = {a: 1, b: 2, ..., z:26};

просто используя оператор распространения, чтобы отделить нежелательное свойство:

const {b, ...rest} = obj;

... и object.assign, чтобы принять только часть отдыха:

const newObj = Object.assign({}, {...rest});

3
restэто уже новый объект - вам не нужна последняя строка. Плюс, это идентично принятому решению.
carpiediem

0
const x = {obj1: 1, pass: 2, obj2: 3, obj3:26};

const objectWithoutKey = (object, key) => {
  const {[key]: deletedKey, ...otherKeys} = object;
  return otherKeys;
}

console.log(objectWithoutKey(x, 'pass'));

1
Хотя этот код может обеспечить решение вопроса, лучше добавить контекст относительно того, почему / как он работает. Это может помочь будущим пользователям учиться и применять эти знания в своем собственном коде. Вы также, вероятно, получите положительные отзывы от пользователей в виде откликов, когда код объясняется.
Борчвм
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.