Düz bir nesneyi ES6 Haritasına nasıl dönüştürebilirim?


128

Bazı nedenlerden dolayı MDN belgelerinde bu basit şeyi bulamıyorum (belki de özlüyorum).

Bunun işe yaramasını bekliyordum:

const map = new Map({foo: 'bar'});

map.get('foo'); // 'bar'

... ama ilk satır atıyor TypeError: (var)[Symbol.iterator] is not a function

Düz bir nesneden nasıl Harita yaparım? İlk önce onu anahtar-değer çiftlerinden oluşan bir diziye dönüştürmem gerekiyor mu?


2
FWIW, bu değer adresinin kabul cevap anahtarlama olabilir mayın için nils' ya BERGI en . Object.entriesGerçekten iyi bir yaklaşım bitti Object.keysve BERGI en jeneratör işlevi yaklaşımı ikisinden de biraz daha doğrudan olduğu Object.keysveya Object.entries.
TJ Crowder

Yanıtlar:


195

Evet, Mapyapıcı bir dizi anahtar-değer çifti alır.

Object.entriesES2017'de (19.1.2.5) bulunan yeni bir Nesne statik yöntemidir .

const map = new Map(Object.entries({foo: 'bar'}));

map.get('foo'); // 'bar'

Şu anda Firefox 46+ ve Edge 14+ ve Chrome'un daha yeni sürümlerinde uygulanmaktadır

Eski ortamları desteklemeniz gerekiyorsa ve aktarma sizin için bir seçenek değilse, georg tarafından önerilen gibi bir çoklu dolgu kullanın:

Object.entries = typeof Object.entries === 'function' ? Object.entries : obj => Object.keys(obj).map(k => [k, obj[k]]);

3
"Çoklu dolgu" oldukça önemsiz olacak:Object.entries = obj => Object.keys(obj).map(k => [k, obj[k]])
georg

4
Object.entriesdüğüm 7.x uygun (bayraksız) indi btw
Lee Benson

2
Yalnızca Node7'deki Object.entries değil, aynı zamanda ES2017 nihai spesifikasyonunun bir parçasıdır. Bu nedenle, kabul edilen cevap bu olmalı, IMO
AnilRedshift 18'17

1
@AnilRedshift - OP, aracılardan kaçınan bir çözüm istediğinden , bu veya jeneratör işlevi yanıtı .
TJ Crowder

2
Ne yazık ki olmayacak.
Nemanja Milosavljevic

78

Lütfen bir jeneratör işlevi kullanarakObject.entries ve / veya bergi'nin cevabını kullanarak sıfırların cevabına bakın . Object.entriesSoru sorulduğunda henüz teknik özelliklerde yer almasa da , Aşama 4'teydi, böylece çoklu doldurmak ve Nisan 2016'da bile kullanmak çok güvenli (sadece). ( Buradaki aşamalarla ilgili daha fazla bilgi .) Ve jeneratör işlevleri ES2015'teydi. OP özellikle aracılardan kaçınmasını istedi ve jeneratör bundan tamamen kaçınmasa da aşağıdakilerden daha iyi bir iş çıkarır veya (biraz) Object.enties.

FWIW, şunu kullanarak Object.entries:

  • Bir dizi oluşturur [name, value]diziler geçmesinenew Map
  • MapYapıcı bir yineleyici elde etmek için bir dizi bir işlevini çağırır; dizi, bir dizi interator nesnesi oluşturur ve döndürür.
  • MapYineleyici nesne girdileri (almak için o yapıcı kullandığı [name, value]diziler) ve harita oluşturmak

Jeneratörü kullanma:

  • Oluşturucu işlevinin çağrılması sonucunda bir üreteç nesnesi oluşturur
  • MapYapıcı ondan bir yineleyici elde etmek için bu jeneratör nesne üzerinde bir işlevini çağırır; jeneratör nesnesi kendini döndürür
  • MapYapıcı (bir yineleyici gibi) jeneratör nesne girişleri (almak için kullandığı [name, value]diziler) ve harita oluşturmak

Yani: Bir tane daha az aracı (dizi Object.entries).

Bununla birlikte, kullanmak Object.entriesdaha basittir ve bu diziyi oluşturmak her zaman bir sorun değildir. Yani gerçekten, ikisi de. Ama ikisi de aşağıdakilerden daha iyi. :-)


Orijinal cevap:

A'yı başlatmak için Map, diziler dizisi gibi anahtar / değer çiftlerini diziler olarak döndüren herhangi bir yineleyici kullanabilirsiniz:

const map = new Map([
    ['foo', 'bar']
]);

Nesneden haritaya yerleşik bir dönüştürme yoktur, ancak şunlarla kolayca yapılabilir Object.keys:

const map = new Map();
let obj = {foo: 'bar'};
Object.keys(obj).forEach(key => {
    map.set(key, obj[key]);
});

Elbette, bunun üstesinden gelmek için kendinize bir işçi işlevi verebilirsiniz:

function buildMap(obj) {
    let map = new Map();
    Object.keys(obj).forEach(key => {
        map.set(key, obj[key]);
    });
    return map;
}

Sonra

const map = buildMap({foo: 'bar'});

Ya da işte daha l33t görünümlü (bu hala bir şey mi?) Versiyon:

function buildMap(obj) {
    return Object.keys(obj).reduce((map, key) => map.set(key, obj[key]), new Map());
}

(Evet, Map#setharita başvuru döndürür. Bazıları bu bir olduğunu iddia ediyorum abusage ait reduce.)

Ya da bilinmezliği gerçekten aşabiliriz:

const buildMap = o => Object.keys(o).reduce((m, k) => m.set(k, o[k]), new Map());

Hayır, bunu asla gerçek yapmam. :-)


1
Ohar en @ ve TJCrowder çözümleri @ füzyon: var buildMap2 = o => new Map(Object.keys(o).map(k => [k, o[k]]));.
7vujy0f0hy

17
Bkz new Map(Object.entries(object)) stackoverflow.com/a/36644558/798133
Rafael Xavier

Object.entries cevapları tercih edilmelidir
Kir

@Kir - O veya jeneratör , evet. Düzenlememe bakın.
TJ Crowder

31

İlk önce onu anahtar-değer çiftlerinden oluşan bir diziye dönüştürmem gerekiyor mu?

Hayır, anahtar-değer çifti dizilerinin bir yineleyicisi yeterlidir. Ara dizi oluşturmaktan kaçınmak için aşağıdakileri kullanabilirsiniz:

function* entries(obj) {
    for (let key in obj)
        yield [key, obj[key]];
}

const map = new Map(entries({foo: 'bar'}));
map.get('foo'); // 'bar'

Güzel bir örnek - sadece başkalarına bir not if(!obj.hasOwnProperties(key)) continue;, nesne prototipinden miras alınan özellikleri vermemenizi sağlamak için for döngüsü koşulundan hemen sonra yapmak isteyebilirsiniz (nesneye güvenmiyorsanız, ancak bunu yine de kullanarak nesneleri yinelerken yapmanız gerekir) iniyi bir alışkanlık olarak).
puiu

2
@Puiu Hayır, yapmamalısın ve bu kötü bir alışkanlık. Nesneye güvenmiyorsanız, .hasOwnPropertymülküne de güvenmemelisiniz ve kullanmak zorundasınızObject.prototype.hasOwnProperty.call(obj, key)
Bergi 21

2
Evet, zahmet etmemek en iyi uygulama olduğunu düşünüyorum. Numaralandırılabilir miras alınan herhangi bir özelliğe sahip olmamak için numaralandırmaya değer tüm nesnelere (yani anahtar-değer-eşlemlerine) güvenmelisiniz. (Ve evet elbette dizileri numaralandırmaktan kaçının ). Nadiren başka bir şeyi numaralandırma durumunuz varsa ve zahmet ediyorsanız, en azından doğru şekilde yapmalısınız call. Orada tavsiye edilen tüm sözleşmelerin obj.hasOwnProperties(key)ne yaptıkları hakkında hiçbir fikri yok gibi görünüyor.
Bergi

3
Bir dönüştürme Objectbir içine Map, pahalı bir işlemdir ve OP özellikle ara-olmayan bir çözelti istedi. Öyleyse neden bu istisnai cevap değil? Bunu sormak muhtemelen nafile, sadece canımı sıkıyor.

1
@tmvnty Türü hecelemeniz gerekebilir function* entries<T>(obj: T): Generator<readonly [keyof T, T[keyof T]]> {…}. Ayrıca yield [key, obj[key]] as const;TypeScript'in dizileri değil tuplelar verdiğini fark etmesine yardımcı olur.
Bergi

11

Nils'in cevabı , çok yararlı bulduğum nesneleri haritalara nasıl dönüştüreceğimi açıklıyor . Ancak OP, bu bilgilerin MDN belgelerinde nerede olduğunu da merak ediyordu. Soru ilk sorulduğunda orada olmasa da, şu anda Object.entries () MDN sayfasında Bir Nesneyi Haritaya Dönüştürme başlığı altında şu ifadeler yer almaktadır :

Bir Nesneyi Haritaya Dönüştürme

new Map()Yapıcı bir iterable kabul entries. İle Object.entries, kolayca dönüştürebilirsiniz Objectiçin Map:

const obj = { foo: 'bar', baz: 42 }; 
const map = new Map(Object.entries(obj));
console.log(map); // Map { foo: "bar", baz: 42 }

7
const myMap = new Map(
    Object
        .keys(myObj)
        .map(
            key => [key, myObj[key]]
        )
)

1
Ohar en @ ve TJCrowder çözümleri @ füzyon: var buildMap2 = o => new Map(Object.keys(o).map(k => [k, o[k]]));.
7vujy0f0hy

Nesne anahtarlarını da sıralamam gerektiği için teşekkürler!
scottwernervt


1

ES6

nesneyi haritaya dönüştür:

const objToMap = (o) => new Map(Object.entries(o));

haritayı nesneye dönüştür:

const mapToObj = (m) => [...m].reduce( (o,v)=>{ o[v[0]] = v[1]; return o; },{} )

Not: mapToObj işlevi, eşleme anahtarlarının dizeler olduğunu varsayar (aksi takdirde başarısız olur)


-1

Bazı JQuery'nin yardımıyla,

const myMap = new Map();
$.each( obj, function( key, value ) {
myMap[key] = value;
});

4
2019'da sorunları çözmek için jquery'ye bakmamamız gerektiğini düşünüyorum.
illcrx

jQuery hala birçok projede ve bu kötü bir cevap değil, sadece optimal değil.
boatcoder
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.