Bir anahtar dışında bir JavaScript nesnesini nasıl klonlayabilirim?


308

Düz bir JS nesnesi var:

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

Bir öğe dışında nesneyi klonlamak istiyorum:

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

Bunu yapmanın en kolay yolu nedir (mümkünse es6 / 7 kullanmayı tercih etmek)?


Orijinal nesneyi değiştirmeden: JSON.parse (JSON.stringify ({... obj, 'key2': undefined}))
infinity1975

Yanıtlar:


441

Eğer kullanırsanız Babel size aşağıdaki sözdizimini kullanabilirsiniz değişken y içine özelliklerinin dinlenme kopya ardından değişken b içine x mülk b kopyalayıp :

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

ve şu adrese aktarılacaktır :

"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
Kodunuzu kullanılmayan değişkenler için tiftik yaparsanız, bu "Kullanılmayan değişken 'b'" ile sonuçlanır. olsa uyarı.
Ross Allen

1
sözdizimi nasıl olsaydılet x = [{a: 1, b: 2, c: 3, z:26}, {a: 5, b: 6, c: 7, z:455}];
ke3pup

14
@RossAllen ignoreRestSiblingsv3.15.0'da (3 Şubat 2017) eklenen bir seçenek var. Bakınız: c59a0ba
Ilya Palkin

4
@IlyaPalkin İlginç. Yine de biraz tembel hissediyor çünkü bkapsamın olduğu gerçeğini değiştirmiyor .
Ross Allen

2
Modül derleme başarısız oluyorsa: SyntaxError: Beklenmedik belirteç, muhtemelen babel dinlenme yayılması dönüşüm eklentisini eklemeniz gerekir. Bkz. Babeljs.io/docs/plugins/transform-object-rest-spread
jsaven

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

veya tanımsız olarak mülk kabul ediyorsanız:

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

7
Mülkü silmek, bunu yapmanın açık ve basit bir yoludur.
sshow

24
Silme ile ilgili uyarı, değişmez bir işlem olmamasıdır.
Javid Jamae

1
bu anahtar tutar
Fareed Alnamrouti

1
Cevabımı düzenlemeden ve silme ifadesini eklemeden önce yorumum yazıldı
Fareed Alnamrouti

Bu tam olarak aradığım şeydi, ama biraz daha farklı bir şekilde biraz daha uygulandı: var cake = {... currentCake, requestorId: undefined};
abelito

73

Ilya Palkin'in cevabına eklemek için: anahtarları dinamik olarak bile kaldırabilirsiniz:

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'de demo

Kaynak:


3
Bu güzel bir sözdizimidir.
Hinrich

2
Bu harika, ama kullanılmayan var deleteKey önlemek için bir yolu var mı? Herhangi bir soruna neden olduğu için değil, JSHint'i şikayet ediyor ve gerçekten kullanmadığımızdan garip görünüyor.
Johnson Wong

6
@JohnsonWong Kullanmayı düşünmediğiniz _bir değişken için hangisinin kullanılmasına izin verilir?
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

ES6'yı kullanamayanlar için lodashveya kullanabilirsiniz underscore.

_.omit(x, 'b')

Veya ramda.

R.omit('b', x)

6
burada atlamayı kullanmak daha mantıklı olmaz mı? _.omit(x, 'b')
tibalt

Teşekkürler @tibalt. Cevabı güncelledi.
Noel Llevares

silme daha özlüdür - lodash, alt çizgi veya ramda kullanmak yalnızca bunları zaten kullanan ve tanıyan projelerle ilgilidir, aksi takdirde bu 2018 ve ötesinde giderek önemsizdir.
jimmont

1
@jimmont delete diğer yanıtlarda zaten belirtilmiştir. Yinelenen cevaplara gerek yok, değil mi? Ve elbette, sadece zaten lodash veya ramda kullananlarla ilgilidir. Ayrıca, yalnızca bu cevapta belirtildiği gibi ES5 ve daha önceki sürümlerle sıkışmış olanlar için de geçerlidir.
Noel Llevares

@dashmug önceki yorumum, bu cevapta temsil edilen yaklaşımı kullanmayı seçerken dikkat edilmesi gereken yaklaşıma (cevabınıza değil) yönelik bir eleştiriydi. Eğer cevapları okuyor olsaydım bu bilgiyi isterdim ve yorumumu eklemekten ve bahsetmemin sebebi budur delete.
jimmont

63

Bu ESNext bir astarını kullanıyorum

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


Genel amaçlı bir işleve ihtiyacınız varsa:

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
Dizide kaydırma yerine ve mapşunları yapabilirsiniz:(({b, c, ...others}) => ({...others}))(obj)
bucabay

@bucabay: Harika! Bu partinin en iyi yanıtı! Standartlara uygun, Düğüm vb. Gibi mükemmel çalışır. Cevap olarak göndermelisiniz.
david.pfx

3
Fantastic answer mate .. <3
Ajithkumar S

5
@totymedli: Bana göre değil. Standart ES6'nın bir parçası olan sözdizimsel formu, okunabilirlik gerekçesiyle her zaman sihirli bir işlev üzerine alacağım.
david.pfx

1
Parlak. Bu kadar.
darksoulsong

22

Bunun için basit bir yardımcı işlev yazabilirsiniz. Lodash aynı isimde benzer bir işlevi vardır: ihmali

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}

Ayrıca, Object.assign'dan daha hızlı olduğuna dikkat edin ve silin: http://jsperf.com/omit-key


11

Belki böyle bir şey:

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

Bu yeterince iyi mi? Yoksa cgerçekten kopyalanamıyor mu?


11

Nesne Yıkmayı Kullanma

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}


Harika bir çözüm!
Denys Mikhalenko

2
Sanırım bu çözüm JSLint 'Kullanılmayan değişken' uyarı önlemek içindir. Ne yazık ki, kullanmak _ESLint için sorunu çözmez ...
bert bruynooghe

6

Bir nesneyi kopyalayıp daha sonra bir mülkü silmeye çalışırken başvuru sorunlarına başvurduğunuz anlaşılıyor. Bir yerde javascript yeni bir değer yaratmak için ilkel değişkenler atamanız gerekir.

Basit hile (korkunç olabilir)

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

Aslında biraz beğendim. Yapabilirdi JSON.parse(JSON.stringify(Object.assign({}, obj, { key2: undefined })));. Silmek zorunda bile değilsiniz, sadece sahte bir değere ihtiyacınız var.
Çad

6

İşte henüz belirtilmediğine inandığım dinamik anahtarları atlamak için bir seçenek:

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

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

removeMeolarak diğer ad olarak adlandırılır removedKeyve yoksayılır. newObjolur { 2: 2, 3: 3, 4: 4 }. Kaldırılan anahtarın mevcut olmadığını, değerin yalnızca olarak ayarlanmadığını unutmayın undefined.


Güzel çözüm. Benzer bir kullanım durumum vardı (redüktörde dinamik anahtar).
ericgio

4

EN KOLAY YOL

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 omit

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

evet, Lodash zarif bir seçenektir, ancak vanilya ES6 ile aynı şeyi elde etmeye çalışıyordum
andreasonny83

3

Bunu yapmak için forma operatörünü de kullanabilirsiniz

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

2
Süper şık görünüyor. Ancak bu, anahtarı tanımsız olarak tutarcopy
kano

böylece sadece orada olanlar tanımsız tuşları kaldırabilirsiniz
Victor

1
kopyadaki ekstra serpme işlemini neden yaptığınızdan emin değilim, const copy = { ...source, b: undefined } tamamen aynı şekilde kaynar.
bert bruynooghe

3

Yapılandırmayı kullanan yukarıdaki çözümler, kullanılmış bir değişkeninizin olması gerçeğinden muzdariptir, bu da ESLint'den şikayet ederseniz, bunu kullanırsanız.

İşte benim çözümlerim:

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

Çoğu platformda (Babel kullanmadığı sürece IE hariç) şunları da yapabilirsiniz:

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


2

Büyük bir değişkenle uğraşıyorsanız, onu kopyalamak ve ardından silmek istemezsiniz, çünkü bu verimsiz olacaktır.

HasOwnProperty denetimine sahip basit bir for-loop çalışmalıdır ve gelecekteki ihtiyaçlara çok daha uyumludur:

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

1
Forma operatörü çözümü, çok daha iyi sözdizimi ile tam olarak aynı şeyi yapar.
david.pfx

2

Peki buna ne dersin? Bu pıtırtı asla bulamadım ama sadece bir veya daha fazla özelliği ekstra bir nesne oluşturmaya gerek kalmadan hariç tutmaya çalışıyordum. Bu işi yapıyor gibi görünüyor ama göremediğim bazı yan etkiler var. Elbette çok okunabilir değil.

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 redüktörünüzden bir örnek olarak bu şekilde başardım:

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

Diğer bir deyişle:

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 yıl önceki kabul edilen cevaba kıyasla çok fazla iş var gibi görünüyor (ve her iki seçenek de birçok tarayıcı için aktarıma dayanıyor).
carpiediem

Benzer bir kullanım durumu (redüktör) var, bu yüzden mutasyon olmadan dinamik tuşları destekleyen güzel bir yol buldum. Temel olarak: const { [removeMe]: removedKey, ...newObj } = obj;- bu soruya cevabımı gör.
goldins

1

Son zamanlarda bunu çok basit bir şekilde yaptım:

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

sadece istenmeyen özelliği ayırmak için forma operatörünü kullanarak :

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

... ve object.assign 'sadece' dinlenme 'kısmını almak için:

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

3
restzaten yeni bir nesne - son satıra ihtiyacınız yok. Ayrıca, bu kabul edilen çözümle aynıdır.
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
Bu kod soruya bir çözüm sunabilse de, neden / nasıl çalıştığına ilişkin bağlam eklemek daha iyidir. Bu, gelecekteki kullanıcıların bu bilgileri öğrenmesine ve kendi kodlarına uygulamalarına yardımcı olabilir. Kod açıklandığında, kullanıcılardan upvotes şeklinde olumlu geri bildirimler almanız da muhtemeldir.
borchvm
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.