ES 6'daki nesneden bazı özellikleri almak için tek astar


153

ES6'da en az yolla sadece birkaç özelliği alan bir işlev nasıl yazılabilir?

Yıkıcı + basitleştirilmiş nesne değişmezi kullanarak çözüm buldum, ancak bu alanların kodda tekrarlanan sevmiyorum.

Daha ince bir çözüm var mı?

(v) => {
    let { id, title } = v;
    return { id, title };
}

Yanıtlar:


124

Alan listesini tekrarlamaktan kaçınmasa da, burada daha ince bir şey var. Parametre ihtiyacını önlemek için "parametre yok etme" işlevini kullanır v.

({id, title}) => ({id, title})

(Buradaki çalıştırılabilir bir örneğe bakın diğer cevaptaki ).

@ EthanBrown'un çözümü daha geneldir. İşte onun özelliklerini kullanan Object.assignve hesaplanan özellikleri ([p] parça) :

function pick(o, ...props) {
    return Object.assign({}, ...props.map(prop => ({[prop]: o[prop]})));
}

configurableSayılamayan ve ayarlayıcılar gibi özelliklerin özelliklerini korumak ve numaralandırılamayan özellikleri atlamak istiyorsak , o zaman:

function pick(o, ...props) {
    var has = p => o.propertyIsEnumerable(p),
        get = p => Object.getOwnPropertyDescriptor(o, p);

    return Object.defineProperties({},
        Object.assign({}, ...props
            .filter(prop => has(prop))
            .map(prop => ({prop: get(props)})))
    );
}

10
+1 güzel cevap, torazaburo; beni haberdar ettiğiniz için teşekkürler Object.assign; es6, altında pek çok hediye bulunan bir Noel ağacı gibidir, tatilden aylar sonra hala hediyeler buluyorum
Ethan Brown

Bir hata oluştu: Özellik açıklaması bir nesne olmalı: undefined. Olmamalı mı filter(...).map(prop => ({[prop]: get(prop)})))?
Sonsuz

İlk pick()uygulamanız için de böyle bir şey yapabilirsinizreturn props.reduce((r, prop) => (r[prop] = o[prop], r), {})
Patrick Roberts

maalesef bu seçim sürümü akış veya daktilo türünde güvenli olmayacaktır. tip güvenliği istiyorsanız, orijinal nesnenin imha ataması etrafında, ardından her birini yeni bir nesneye atamanın bir yolu yoktur.
duhseekoh

Bir özellik bir nesnede yoksa, elde edersiniz undefined. Bazen önemlidir. Bunun dışında güzel bir fikir.
x-yuri

43

Cevabınızdan (veya torazburo'lardan) çok daha kompakt hale getirmenin bir yolu olduğunu düşünmüyorum, ancak aslında yapmaya çalıştığınız şey Underscore'un pickçalışmasını taklit etmektir . Bunu ES6'da yeniden uygulamak yeterince kolay olurdu:

function pick(o, ...fields) {
    return fields.reduce((a, x) => {
        if(o.hasOwnProperty(x)) a[x] = o[x];
        return a;
    }, {});
}

Sonra kullanışlı bir yeniden kullanılabilir fonksiyonunuz var:

var stuff = { name: 'Thing', color: 'blue', age: 17 };
var picked = pick(stuff, 'name', 'age');

Teşekkürler. Bu sorumun cevabı değil, çok güzel bir ek.
kirilloid

7
(omuz silkme) böyle ben hissediyorum olan senin çözümü için bir cevap; daha ince bir genel çözüm yoktur (torazaburo'nun çözümü fazladan döküntüden çıkarılır, ancak temel sorun - tüm mülk adlarının iki kez yazılması gerekir - çözümünüzden daha iyi ölçeklenmediği anlamına gelir). Çözümüm en azından iyi ölçekleniyor ... pickişlevi bir kez doğru yapın ve istediğiniz kadar özellik seçebilirsiniz ve bunları iki katına çıkarmaz.
Ethan Brown

1
Neden kullanıyorsun hasOwnProperty? Alanlar elle seçilirse, indaha uygun görünebilir; Ben kontrol tamamen atlamak ve sadece varsayılan izin için gitmek istiyorum rağmen undefined.
Bergi

Bergi, bu makul bir nokta ... Ben sadece bir prototip zinciri özellikleri (yöntemleri değil) garip ve "koklamak" (kod kokusu olduğu gibi) olarak düşünün, ve ben bunları varsayılan olarak filtre tercih ederim. Prototip özelliklerine ihtiyaç duyan bir uygulama varsa, ... bunun için bir seçenek olabilir.
Ethan Brown

Ya json dizileri!
Rizwan Patel

19

Bunu tek katmanlı olarak çözmenin hilesi, alınan yaklaşımı tersine çevirmektir: Orijinal nesneden başlamak yerine orig çıkarmak istedikleri anahtarlardan başlayabilir.

Array#reduceBirini kullanmak daha sonra gerekli her anahtarı,initialValue adı geçen işlev için .

Şöyle ki:

const orig = {
  id: 123456789,
  name: 'test',
  description: '…',
  url: 'https://…',
};

const filtered = ['id', 'name'].reduce((result, key) => { result[key] = orig[key]; return result; }, {});

console.log(filtered); // Object {id: 123456789, name: "test"}


11

Virgül operatörünü kullanarak biraz daha kısa bir çözüm:

const pick = (O, ...K) => K.reduce((o, k) => (o[k]=O[k], o), {})

console.log(
  pick({ name: 'John', age: 29, height: 198 }, 'name', 'age')
)  


nasıl kullanılır? Bir örnek verebilir misiniz?
Tomas M

1
Tıpkı pickbu konudaki diğer fonksiyonlar gibi çalışıyor :pick({ name: 'John', age: 29, height: 198 }, 'name', 'age')
shesek

8

TC39'un nesne dinlenme / yayılma özellikleri teklifi , bu oldukça kaygan olacaktır:

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

( Gereksinim duymayabileceğiniz xve ydeğişkenleri yaratmanın dezavantajı vardır .)


33
Bu uygun bir form omit, ama değilpick
kirilloid

5
Bir ES teklifi olarak bunun tam tersini yapan bir varyantı görmek let { a, b } as z = { x: 1, y: 2, a: 3, b: 4 }
isterim

3

Var olan nesneden özellikleri açmak ve bunları farklı adlara sahip değişkenlere atamak için yeni ve başlangıçta boş bir nesnenin alanlarını kullanabilirsiniz.

const person = {
  fname: 'tom',
  lname: 'jerry',
  aage: 100,
}

let newPerson = {};

({fname: newPerson.fname, lname: newPerson.lname} = person);

console.log(newPerson);


(index): 36 Yakalanmamış
Sözdizimi Hatası

@Remzes bunu nerede ve nasıl yürüttüğünüzü bilmiyor, ancak SO kod düzenleyicisinde ve krom geliştirici araçlarında iyi çalışıyor.
Saksham

Ben jsfiddle kullandım
16'da Remzes

Cevabınızı biraz geliştirdim, ancak OP'nin talep ettiği şeyle ilgili hala çok ayrıntılı. Yalnızca alan adlarını değil, aynı zamanda yeni nesnenin adını da tekrarlar.
Dan Dascalescu

3

ES6, sorunun yazıldığı zamanki en son spesifikasyondu. Bu cevapta açıklandığı gibi , anahtar toplama ES2019'da ES6'dan önemli ölçüde daha kısadır:

Object.fromEntries(
  Object.entries(obj)
  .filter(([key]) => ['foo', 'bar'].includes(key))
)

2

Şu anda JavaScript'in nesne kısayol sözdizimini geliştirmek için, adlandırılmış özelliklerin tekrarlanmadan "seçilmesini" sağlayacak bir strawman teklifi var:

const source = {id: "68646", genre: "crime", title: "Scarface"};
const target = {};
Object.assign(target, {source.title, source.id});

console.log(picked);
// {id: "68646", title: "Scarface"}

Ne yazık ki, teklif yakında herhangi bir yere gitmiyor gibi görünüyor. En son Temmuz 2017'de düzenlendi ve hala Aşama 0'da , yazarın hendekte veya unutmuş olabileceğini gösteren bir taslak .

ES5 ve öncesi (katı olmayan mod)

Düşündüğüm kısaca, kimsenin artık kullanmadığı eski bir dil özelliği içeriyor :

Object.assign(target, {...(o => {
    with(o) return { id, title };
})(source)});

withifadeler katı modda yasaktır, bu da modern JavaScript'in% 99,999'u için bu yaklaşımı işe yaramaz hale getirir. Biraz utanç verici, çünkü bu withözellik için bulduğum tek yarım kullanımlık kullanım . 😀


1

Ethan Brown'ın çözümüne benziyorum, ama daha kısa - pickişlev. Başka bir işlev pick2biraz daha uzun (ve daha yavaş), ancak özellikleri ES6'ya benzer şekilde yeniden adlandırmaya izin veriyor.

const pick = (o, ...props) => props.reduce((r, p) => p in o ? {...r, [p]: o[p]} : r, {})

const pick2 = (o, ...props) => props.reduce((r, expr) => {
  const [p, np] = expr.split(":").map( e => e.trim() )
  return p in o ? {...r, [np || p]: o[p]} : r
}, {}) 

Kullanım örneği:

const d = { a: "1", c: "2" }

console.log(pick(d, "a", "b", "c"))        // -> { a: "1", c: "2" }
console.log(pick2(d, "a: x", "b: y", "c")) // -> { x: "1", c: "2" }

1
Downvote'un nedeni nedir? Senin için çalışmıyor mu?
Alexandr Priezzhev

0

Bu çözümü istemiştim, ancak önerilen anahtarların mevcut olup olmadığını bilmiyordum. Bu yüzden @torazaburo yanıtını aldım ve kullanım durumum için geliştirdim:

function pick(o, ...props) {
  return Object.assign({}, ...props.map(prop => {
    if (o[prop]) return {[prop]: o[prop]};
  }));
}

// Example:
var person = { name: 'John', age: 29 };
var myObj = pick(person, 'name', 'sex'); // { name: 'John' }

0

https://stackoverflow.com/users/865693/shesek'in azaltma yaklaşımından esinlenerek :

const pick = (orig, ...keys) => keys.reduce((acc, key) => ({...acc, [key]: orig[key]}), {})

kullanımı:

pick({ model : 'F40', manufacturer: 'Ferrari', productionYear: 1987 }, 'model', 'productionYear') sonuç: {model: "F40", productionYear: 1987}

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.