Jak sklonować obiekt JavaScript z wyjątkiem jednego klucza?

307

Mam płaski obiekt JS:

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

Chcę sklonować obiekt z wyjątkiem jednego elementu:

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

Jaki jest najłatwiejszy sposób na zrobienie tego (wolę używać ES6 / 7, jeśli to możliwe)?

lis
źródło
Bez zmiany oryginalnego obiektu: JSON.parse (JSON.stringify ({... obj, 'key2': undefined}))
infinity1975

Odpowiedzi:

440

Jeśli używasz Babel , możesz użyć następującej składni, aby skopiować właściwość bz x do zmiennej b, a następnie skopiować pozostałe właściwości do zmiennej y :

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

i zostanie przełożony na:

"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"]);
Ilya Palkin
źródło
58
Jeśli podszyjesz kod w poszukiwaniu nieużywanych zmiennych, spowoduje to „Nieużywaną zmienną„ b ”. jednak ostrzeżenie.
Ross Allen
1
jak wyglądałaby składnia, gdybyś miałlet x = [{a: 1, b: 2, c: 3, z:26}, {a: 5, b: 6, c: 7, z:455}];
ke3pup
14
@RossAllen Istnieje opcja, ignoreRestSiblingsktóra została dodana w wersji 3.15.0 (3 lutego 2017 r.). Zobacz: commit c59a0ba
Ilya Palkin
4
@IlyaPalkin Ciekawe. Jest to jednak trochę leniwe, ponieważ nie zmienia to faktu, że istnieje bzakres.
Ross Allen,
2
Jeśli otrzymujesz kompilację modułu nie powiodło się: Błąd składni: nieoczekiwany token, prawdopodobnie musisz dodać wtyczkę transformacji rozprzestrzeniania babel. Zobacz babeljs.io/docs/plugins/transform-object-rest-spread
jsaven 20.01.2018
133
var clone = Object.assign({}, {a: 1, b: 2, c: 3});
delete clone.b;

lub jeśli akceptujesz własność jako niezdefiniowaną:

var clone = Object.assign({}, {a: 1, b: 2, c: 3}, {b: undefined});
madox2
źródło
7
Po prostu usunięcie właściwości jest jasnym i prostym sposobem na zrobienie tego.
pokaz
24
Zastrzeżenie dotyczące usuwania polega na tym, że nie jest to niezmienna operacja.
Javid Jamae,
1
to utrzymuje klucz
Fareed Alnamrouti
1
Mój komentarz został napisany przed edycją odpowiedzi i dodaniem instrukcji usuwania
Fareed Alnamrouti
Właśnie tego szukałem, ale nieco bardziej zaimplementowałem w nieco inny sposób: var cake = {... currentCake, requestorId: undefined};
abelito,
73

Aby dodać do odpowiedzi Ilyi Palkin: możesz nawet dynamicznie usuwać klucze:

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};

Demo w Babel REPL

Źródło:

Paul Kögel
źródło
3
To niezła składnia.
Hinrich
2
To świetnie, ale czy jest sposób, aby uniknąć nieużywanego var deleteKey? Nie dlatego, że powoduje problemy, ale sprawia, że ​​JSHint narzeka i wydaje się dziwny, ponieważ tak naprawdę go nie używamy.
Johnson Wong,
6
@JohnsonWong Co powiesz na użycie _dozwolonej zmiennej, której nie zamierzasz używać?
Ryan H.,
var b = {a:44, b:7, c:1}; let {['a']:z, ...others} = b; console.log(z , others ); // logs: 44, {b:7, c:1}
styczeń
70

Dla tych, którzy nie mogą korzystać z ES6, możesz użyć lodashlub underscore.

_.omit(x, 'b')

Lub ramda.

R.omit('b', x)
Noel Llevares
źródło
6
czy nie byłoby bardziej logiczne użycie tutaj pominięcia ? _.omit(x, 'b')
tibalt
Dzięki @tibalt. Zaktualizowałem odpowiedź o to.
Noel Llevares
usunięcie jest bardziej zwięzłe - użycie lodash, podkreślenia lub ramdy dotyczy tylko projektów, które już je wykorzystują i znają, w przeciwnym razie staje się to coraz bardziej nieistotne w 2018 r. i później.
Jimmont
1
@jimmont delete jest już wspomniany w innych odpowiedziach. Nie ma potrzeby duplikowania odpowiedzi, nie sądzisz? I oczywiście dotyczy to tylko tych, którzy już używają lodash lub ramda. Dotyczy to również tych, którzy utknęli w ES5 i wcześniejszych, jak stwierdzono w tej odpowiedzi.
Noel Llevares,
@dashmug mój poprzedni komentarz był krytyką podejścia (a nie twojej odpowiedzi), na które należy zwrócić uwagę przy wyborze podejścia przedstawionego w tej odpowiedzi. Chciałbym uzyskać te informacje, gdybym czytał odpowiedzi i jest to powód do dodania mojego komentarza i wzmianki delete.
Jimmont,
63

Używam tej wkładki 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)


Jeśli potrzebujesz funkcji ogólnego przeznaczenia:

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)

Vdegenne
źródło
9
Zamiast owijania w tablicę i mapmożesz zrobić:(({b, c, ...others}) => ({...others}))(obj)
bucabay
@bucabay: Genialny! To najlepsza odpowiedź z wielu! Zgodny ze standardami, działa idealnie w Węzle itp. Należy przesłać jako odpowiedź.
david.pfx
3
Fantastyczna odpowiedź kolego .. <3
Ajithkumar S
5
@totymedli: Nie przeze mnie. Przyjmę formę syntaktyczną, część standardowego ES6, zamiast funkcji magicznej w dowolnym momencie, ze względu na czytelność.
david.pfx
1
Znakomity. To wszystko.
darksoulsong
22

Możesz napisać dla niego prostą funkcję pomocniczą. Lodash ma podobną funkcję o tej samej nazwie: pomiń

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}

Pamiętaj też, że jest szybszy niż Object.assign, a następnie usuń: http://jsperf.com/omit-key

just-boris
źródło
11

Może coś takiego:

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

Czy to wystarczy? A może nie można cgo skopiować?

clean_coding
źródło
11

Korzystanie z destrukcji obiektów

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}

Ivan Nosov
źródło
Świetne rozwiązanie!
Denys Mikhalenko
2
Myślę, że to rozwiązanie ma zapobiec ostrzeżeniu „Nieużywana zmienna” w JSLint. Niestety używanie _nie rozwiązuje problemu dla ESLint ...
bert bruynooghe
6

Hej, wygląda na to, że napotykasz problemy, gdy próbujesz skopiować obiekt, a następnie usunąć właściwość. Gdzieś trzeba przypisać prymitywne zmienne, aby javascript tworzył nową wartość.

To była prosta sztuczka (może być przerażająca)

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"}
Chris Fust
źródło
Właściwie to mi się podoba. Mógłbym zrobić JSON.parse(JSON.stringify(Object.assign({}, obj, { key2: undefined })));. Nawet nie musisz go usuwać, wystarczy wartość falsy.
Czad
6

Oto opcja pominięcia kluczy dynamicznych, które moim zdaniem nie zostały jeszcze wspomniane:

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

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

removeMejest aliasowany removedKeyi ignorowany. newObjstaje się { 2: 2, 3: 3, 4: 4 }. Zauważ, że usunięty klucz nie istnieje, wartość nie została tylko ustawiona na undefined.

Goldins
źródło
Niezłe rozwiązanie. Miałem podobny przypadek użycia (dynamiczny klucz w reduktorze).
ericgio
4

NAJPROSTSZY SPOSÓB

const allAlphabets = {a: 1, b: 2, c: 3, ..., z:26};
const { b, ...allExceptOne } = allAlphabets;
console.log(allExceptOne);   // {a: 1, c: 3, ..., z:26}
Android Ocean
źródło
3

Lodash pomiń

let source = //{a: 1, b: 2, c: 3, ..., z:26}
let copySansProperty = _.omit(source, 'b');
// {a: 1, c: 3, ..., z:26}
OscarRyz
źródło
tak, Lodash to elegancka opcja, ale starałem się osiągnąć to samo z wanilią ES6
andreasonny83
3

W tym celu możesz również użyć operatora rozprzestrzeniania

const source = { a: 1, b: 2, c: 3, z: 26 }
const copy = { ...source, ...{ b: undefined } } // { a: 1, c: 3, z: 26 }
Mickael M.
źródło
2
Wygląda na fajne. To jednak utrzymuje klucz jako niezdefiniowany wcopy
kano
więc możesz usunąć niezdefiniowane klucze, jeśli są tylko te, które się tam znajdują
Victor
1
nie jestem pewien, dlaczego dodatkowo rozłożyłeś w kopii, const copy = { ...source, b: undefined } sprowadza się do dokładnie tego samego.
bert bruynooghe
3

Powyższe rozwiązania wykorzystujące strukturalizację cierpią na to, że masz używaną zmienną, co może powodować skargi ze strony ESLint, jeśli z niej korzystasz.

Oto moje rozwiązania:

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

Na większości platform (oprócz IE, chyba że używasz Babel), możesz także:

const src = { a: 1, b: 2 }
const result = Object.fromEntries(
  Object.entries(src).filter(k => k !== 'b'))
Bert Bruynooghe
źródło
3

Co powiesz na to:

let clone = Object.assign({}, value);
delete clone.unwantedKey;
Lars Juel Jensen
źródło
2

Jeśli masz do czynienia z dużą zmienną, nie chcesz jej kopiować, a następnie usuwać, ponieważ byłoby to nieefektywne.

Prosta pętla for z funkcją hasOwnProperty powinna działać i jest o wiele bardziej przystosowalna do przyszłych potrzeb:

for(var key in someObject) {
        if(someObject.hasOwnProperty(key) && key != 'undesiredkey') {
                copyOfObject[key] = someObject[key];
        }
}
HoldOffHunger
źródło
1
Rozwiązanie operatora rozprzestrzeniania robi dokładnie to samo z dużo ładniejszą składnią.
david.pfx
2

A co z tym? Nigdy nie znalazłem tego tupotu, ale próbowałem po prostu wykluczyć jedną lub więcej właściwości bez potrzeby tworzenia dodatkowego obiektu. Wydaje się, że to działa, ale są pewne skutki uboczne, których nie jestem w stanie zobaczyć. Na pewno nie jest bardzo czytelny.

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

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

/**
a: {
   publicKey: 'public is safe',
   somethingElse: true,
}
*/
andreasonny83
źródło
2

Dokonałem tego w ten sposób, jako przykład z mojego reduktora Redux:

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

Innymi słowy:

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
Jonathan Tuzman
źródło
Wydaje się, że to dużo dodatkowej pracy, w porównaniu do zaakceptowanej odpowiedzi sprzed 3 lat (i obie opcje polegają na transpozycji do wielu przeglądarek).
carpiediem
Mam podobny przypadek użycia (reduktor), więc wymyśliłem fajny sposób, który obsługuje klucze dynamiczne bez mutacji. Zasadniczo: const { [removeMe]: removedKey, ...newObj } = obj;- patrz moja odpowiedź na to pytanie.
goldins
1

Ostatnio zrobiłem to w bardzo prosty sposób:

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

wystarczy użyć operatora rozkładania, aby oddzielić niepożądaną właściwość:

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

... i object.ignign, aby wziąć tylko część „odpoczynku”:

const newObj = Object.assign({}, {...rest});
Pepdbm 7
źródło
3
restjest już nowym obiektem - nie potrzebujesz ostatniej linii. Ponadto jest to identyczne z przyjętym rozwiązaniem.
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'));
ghiles ybeggazene
źródło
1
Chociaż ten kod może dostarczyć rozwiązania pytania, lepiej jest dodać kontekst wyjaśniający, dlaczego / jak to działa. Może to pomóc przyszłym użytkownikom w nauce i zastosowaniu tej wiedzy do własnego kodu. Prawdopodobnie będziesz mieć pozytywne opinie od użytkowników w postaci pozytywnych opinii, gdy kod zostanie wyjaśniony.
borchvm