Как преобразовать простой объект в карту ES6?
По какой-то причине я не могу найти эту простую вещь в документах MDN (возможно, я просто пропустил ее).
Я ожидал, что это сработает:
const map = new Map({foo: 'bar'});
map.get('foo'); // 'bar'
... но первая строка выбрасывает TypeError: (var)[Symbol.iterator] is not a function
Как создать карту из простого объекта? Должен ли я сначала преобразовать его в массив массивов пар ключ-значение?
Ответы
Ответ 1
Для инициализации Map
вы можете использовать любой итератор, который возвращает пары ключ/значение в виде массивов, например массив массивов:
const map = new Map([
['foo', 'bar']
]);
Нет никакого встроенного преобразования от объекта к карте, но это легко сделать с помощью Object.keys
:
const map = new Map();
let obj = {foo: 'bar'};
Object.keys(obj).forEach(key => {
map.set(key, obj[key]);
});
Вы можете, конечно, дать себе рабочую функцию для обработки этого:
function buildMap(obj) {
let map = new Map();
Object.keys(obj).forEach(key => {
map.set(key, obj[key]);
});
return map;
}
Тогда
const map = buildMap({foo: 'bar'});
Или здесь более l33t-выглядящий (это что-то еще?) версия:
function buildMap(obj) {
return Object.keys(obj).reduce((map, key) => map.set(key, obj[key]), new Map());
}
(Да, Map#set
возвращает ссылку на карту. Некоторые утверждают, что это злоупотребление reduce
.)
Или мы действительно можем пережить верх над неизвестностью:
const buildMap = o => Object.keys(o).reduce((m, k) => m.set(k, o[k]), new Map());
Нет, я бы никогда не сделал этого по-настоящему.: -)
Ответ 2
Да, конструктор Map
принимает массив пар ключ-значение.
Существует предложение ES Stage4 для Object.entries
, которое возвращает массив значений ключа для объекта:
const map = new Map(Object.entries({foo: 'bar'}));
map.get('foo'); // 'bar'
В настоящее время он реализован в Firefox 46+ и Edge 14+ (и за флагом в Chrome).
Если транспиляция не является для вас вариантом, посмотрите на ответ TJ Crowder или используйте polyfill, например, рекомендованный georg:
Object.entries = typeof Object.entries === 'function' ? Object.entries : obj => Object.keys(obj).map(k => [k, obj[k]]);
Обновление 19.09.2017: оно в ES2017
Как упоминалось в комментариях AnilRedshift, Object.entries
теперь является частью окончательной спецификации ES2017 (19.1.2.5).
Ответ 3
Нужно ли мне сначала преобразовать его в массив массивов пар ключ-значение?
Нет, достаточно итератора пар ключей-значений. Вы можете использовать следующее, чтобы избежать создания промежуточного массива:
function* entries(obj) {
for (let key in obj)
yield [key, obj[key]];
}
const map = new Map(entries({foo: 'bar'}));
map.get('foo'); // 'bar'
Ответ 4
const myMap = new Map(
Object
.keys(myObj)
.map(
key => [key, myObj[key]]
)
)
Ответ 5
В качестве альтернативы вы можете использовать метод lodash toPairs:
const _ = require('lodash');
const map = new Map(_.toPairs({foo: 'bar'}));