Bagaimana saya bisa mengkloning objek JavaScript kecuali satu kunci?

308

Saya memiliki objek JS datar:

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

Saya ingin mengkloning objek kecuali satu elemen:

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

Apa cara termudah untuk melakukan ini (lebih suka menggunakan es6 / 7 jika mungkin)?

rubah
sumber
Tanpa mengubah objek asli: JSON.parse (JSON.stringify ({... obj, 'key2': undefined}))
infinity1975

Jawaban:

441

Jika Anda menggunakan Babel, Anda dapat menggunakan sintaks berikut untuk menyalin properti b dari x ke dalam variabel b dan kemudian menyalin sisa properti ke dalam variabel y :

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

dan itu akan diubah menjadi:

"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
sumber
58
Jika Anda membasahi kode untuk variabel yang tidak digunakan, ini akan menghasilkan "Variabel yang tidak digunakan 'b'." peringatan sekalipun.
Ross Allen
1
bagaimana sintaksisnya jika Anda punyalet x = [{a: 1, b: 2, c: 3, z:26}, {a: 5, b: 6, c: 7, z:455}];
ke3pup
14
@RossAllen Ada opsi ignoreRestSiblingsyang ditambahkan di v3.15.0 (3 Februari 2017). Lihat: commit c59a0ba
Ilya Palkin
4
@IlyaPalkin Menarik. Rasanya agak malas karena tidak mengubah fakta bahwa ada bruang lingkup.
Ross Allen
2
Jika Anda gagal membuat Modul build: SyntaxError: Token yang tidak terduga, Anda mungkin perlu menambahkan plugin transformabel babel rest spread. Lihat babeljs.io/docs/plugins/transform-object-rest-spread
jsaven
133
var clone = Object.assign({}, {a: 1, b: 2, c: 3});
delete clone.b;

atau jika Anda menerima properti tidak terdefinisi:

var clone = Object.assign({}, {a: 1, b: 2, c: 3}, {b: undefined});
madox2
sumber
7
Cukup menghapus properti adalah cara yang jelas dan sederhana untuk melakukannya.
sshow
24
Peringatan dengan delete adalah bahwa ini bukan operasi yang tidak dapat diubah.
Javid Jamae
1
ini menjaga kuncinya
Fareed Alnamrouti
1
Komentar saya ditulis sebelum ia mengedit jawabannya dan menambahkan pernyataan hapus
Fareed Alnamrouti
Ini persis apa yang saya cari, tetapi sedikit lebih diterapkan dengan cara yang sedikit berbeda: var cake = {... currentCake, requestorId: undefined};
abelito
73

Untuk menambah jawaban Ilya Palkin: Anda bahkan dapat menghapus kunci secara dinamis:

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 dalam Babel REPL

Sumber:

Paul Kögel
sumber
3
Ini adalah sintaks yang bagus.
Hinrich
2
Ini hebat, tetapi apakah ada cara untuk menghindari var deleteKey yang tidak digunakan? Bukannya itu menyebabkan masalah, tapi membuat JSHint mengeluh, dan memang terlihat aneh karena kita benar-benar tidak menggunakannya.
Johnson Wong
6
@ JohnsonWong Bagaimana kalau menggunakan _yang diizinkan untuk variabel yang tidak ingin Anda gunakan?
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}
Jimmont
70

Bagi yang tidak bisa menggunakan ES6, Anda bisa menggunakan lodashatau underscore.

_.omit(x, 'b')

Atau ramda.

R.omit('b', x)
Noel Llevares
sumber
6
bukankah lebih logis untuk menggunakan menghilangkan di sini? _.omit(x, 'b')
tibalt
Terima kasih @tibalt. Diperbarui jawabannya dengan itu.
Noel Llevares
hapus lebih ringkas - menggunakan lodash, garis bawah atau ramda hanya relevan untuk proyek yang sudah menggunakan dan mengetahuinya, jika tidak, ini semakin tidak relevan pada 2018 dan seterusnya.
Jimmont
1
@jimmont delete sudah disebutkan dalam jawaban lain. Tidak perlu jawaban rangkap, bukan begitu? Dan tentu saja, ini hanya relevan bagi mereka yang sudah menggunakan lodash atau ramda. Dan itu juga hanya relevan untuk mereka yang terjebak dengan ES5 dan sebelumnya seperti yang dinyatakan dalam jawaban ini.
Noel Llevares
@dashmug komentar saya sebelumnya adalah kritik terhadap pendekatan (bukan jawaban Anda) yang harus dicatat ketika memilih untuk menggunakan pendekatan yang diwakili dalam jawaban ini. Saya ingin informasi ini jika saya membaca jawaban dan merupakan alasan untuk menambahkan komentar dan penyebutan saya delete.
Jimmont
63

Saya menggunakan ESNext one liner ini

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


Jika Anda membutuhkan fungsi tujuan umum:

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
sumber
9
Alih-alih membungkus dalam array dan mapAnda dapat melakukan:(({b, c, ...others}) => ({...others}))(obj)
bucabay
@bucabay: Cemerlang! Itulah jawaban terbaik dari semuanya! Sesuai standar, berfungsi sempurna di Node dll. Anda harus mengirimkan sebagai jawaban.
david.pfx
3
Pasangan jawaban yang fantastis .. <3
Ajithkumar S
5
@totymedli: Bukan oleh saya. Saya akan mengambil bentuk sintaksis, bagian dari ES6 standar, atas fungsi ajaib kapan saja, dengan alasan keterbacaan.
david.pfx
1
Cemerlang. Itu saja.
darksoulsong
22

Anda dapat menulis fungsi pembantu sederhana untuk itu. Lodash memiliki fungsi serupa dengan nama yang sama: menghilangkan

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}

Juga, perhatikan bahwa ini lebih cepat dari Object.assign dan hapus kemudian: http://jsperf.com/omit-key

adil-boris
sumber
11

Mungkin kira-kira seperti ini:

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

Apakah ini cukup baik? Atau tidak dapat cbenar - benar disalin?

clean_coding
sumber
11

Menggunakan Destrukturisasi Objek

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
sumber
Solusi bagus!
Denys Mikhalenko
2
Saya kira solusi ini dimaksudkan untuk mencegah peringatan 'variabel yang tidak digunakan' di JSLint. Sayangnya, menggunakan _tidak menyelesaikan masalah untuk ESLint ...
bert bruynooghe
6

Hei sepertinya Anda mengalami masalah referensi ketika Anda mencoba menyalin objek kemudian menghapus properti. Di suatu tempat Anda harus menetapkan variabel primitif sehingga javascript membuat nilai baru.

Trik sederhana (mungkin menghebohkan) yang saya gunakan adalah ini

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
sumber
Aku sebenarnya menyukainya. Bisa lakukan JSON.parse(JSON.stringify(Object.assign({}, obj, { key2: undefined })));. Bahkan tidak perlu menghapusnya, hanya perlu nilai palsu.
Chad
6

Berikut adalah opsi untuk menghilangkan kunci dinamis yang saya yakin belum disebutkan:

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

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

removeMealias removedKeydan diabaikan. newObjmenjadi { 2: 2, 3: 3, 4: 4 }. Perhatikan bahwa kunci yang dihapus tidak ada, nilainya tidak hanya diatur ke undefined.

goldins
sumber
Solusi bagus Saya memiliki kasus penggunaan yang sama (kunci dinamis dalam peredam).
ericgio
4

CARA TERMUDAH

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
sumber
3

Lodash omit

let source = //{a: 1, b: 2, c: 3, ..., z:26}
let copySansProperty = _.omit(source, 'b');
// {a: 1, c: 3, ..., z:26}
OscarRyz
sumber
ya, Lodash adalah opsi yang elegan, tetapi saya mencoba untuk mencapai hal yang sama dengan vanilla ES6
andreasonny83
3

Anda juga dapat menggunakan operator spread untuk melakukan ini

const source = { a: 1, b: 2, c: 3, z: 26 }
const copy = { ...source, ...{ b: undefined } } // { a: 1, c: 3, z: 26 }
Mickael M.
sumber
2
Tampak super bagus. Namun ini menjaga kuncinya sebagai tidak terdefinisi dalamcopy
kano
sehingga Anda dapat menghapus kunci yang tidak ditentukan jika ada satu-satunya yang ada di sana
Victor
1
tidak yakin mengapa Anda melakukan penyebaran ekstra di salinan, const copy = { ...source, b: undefined } bermuara persis sama.
bert bruynooghe
3

Solusi di atas menggunakan penataan menderita dari fakta bahwa Anda memiliki variabel yang digunakan, yang dapat menyebabkan keluhan dari ESLint jika Anda menggunakannya.

Jadi, inilah solusi saya:

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

Pada sebagian besar platform (kecuali IE kecuali menggunakan Babel), Anda juga dapat melakukan:

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

Bagaimana dengan ini:

let clone = Object.assign({}, value);
delete clone.unwantedKey;
Lars Juel Jensen
sumber
2

Jika Anda berurusan dengan variabel besar, Anda tidak ingin menyalinnya dan kemudian menghapusnya, karena ini tidak efisien.

Sederhana untuk-loop dengan cek hasOwnProperty harus bekerja, dan itu jauh lebih mudah beradaptasi dengan kebutuhan di masa depan:

for(var key in someObject) {
        if(someObject.hasOwnProperty(key) && key != 'undesiredkey') {
                copyOfObject[key] = someObject[key];
        }
}
HoldOffHunger
sumber
1
Solusi operator menyebar tidak persis sama dengan sintaks yang jauh lebih baik.
david.pfx
2

Bagaimana dengan ini? Saya tidak pernah menemukan derai ini di sekitar tetapi saya hanya mencoba untuk mengecualikan satu atau lebih properti tanpa perlu membuat objek tambahan. Ini sepertinya berhasil, tetapi ada beberapa efek samping yang tidak dapat saya lihat. Yang pasti tidak terlalu mudah dibaca.

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
sumber
2

Saya melakukannya dengan cara ini, sebagai contoh dari redux Redux saya:

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

Dengan kata lain:

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
sumber
Sepertinya banyak pekerjaan tambahan, dibandingkan dengan jawaban yang diterima dari 3 tahun yang lalu (dan kedua opsi bergantung pada pengalihan untuk banyak browser).
carpiediem
Saya memiliki use case yang serupa (reducer) jadi saya datang dengan cara yang bagus yang mendukung tombol dinamis tanpa mutasi. Pada dasarnya: const { [removeMe]: removedKey, ...newObj } = obj;- lihat jawaban saya pada pertanyaan ini.
goldins
1

Baru-baru ini saya melakukannya dengan cara yang sangat sederhana:

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

hanya menggunakan operator spread untuk memisahkan properti yang tidak diinginkan:

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

... dan objek.tugaskan untuk mengambil hanya bagian 'sisanya':

const newObj = Object.assign({}, {...rest});
Pepdbm 7
sumber
3
restsudah menjadi objek baru - Anda tidak perlu baris terakhir. Plus, ini identik dengan solusi yang diterima.
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
sumber
1
Meskipun kode ini dapat memberikan solusi untuk pertanyaan, lebih baik menambahkan konteks mengapa / cara kerjanya. Ini dapat membantu pengguna di masa depan belajar, dan menerapkan pengetahuan itu ke kode mereka sendiri. Anda juga cenderung mendapat umpan balik positif dari pengguna dalam bentuk upvotes, ketika kode dijelaskan.
borchvm