将Map转换为JavaScript对象

77

我有下面这段JavaScript代码,其中包括一个键/值对,将一个嵌套的路径映射到一个目录。

function createPaths(aliases, propName, path) {
    aliases.set(propName, path);
}

map = new Map();

createPaths(map, 'paths.aliases.server.entry', 'src/test');
createPaths(map, 'paths.aliases.dist.entry', 'dist/test');

现在我想做的是从地图中的键创建JSON对象。

它必须是这样的,

paths: {
  aliases: {
    server: {
      entry: 'src/test'
    },
    dist: {
      entry: 'dist/test'
    }
  }
}

我不确定是否有现成的方法来解决这个问题。感谢您的帮助。


我会从带有点的字符串中减去键名,然后从所收集的内容构建对象。 - Nonemoticoner
我讨厌人们不声明变量最终导致全局变量的情况。另外,请记住,“将JSON对象字面值称为“JSON对象”是一个常见错误。JSON不能是一个对象,而是一种字符串格式。”(来自W3Schools - Capt 171
6个回答

170

根据MDN提供的信息,fromEntries()在Node v12中可用:

const map1 = new Map([
  ['foo', 'bar'],
  ['baz', 42]
]);

const obj = Object.fromEntries(map1);
// { foo: 'bar', baz: 42 }

将对象转换回地图:

const map2 = new Map(Object.entries(obj));
// Map(2) { 'foo' => 'bar', 'baz' => 42 }

2
请记住,Map 可以保存非字符串键,因此在 new Map([[{x: 0, y: 1}, 42]]) 这样的情况下,您将得到一个不希望出现的结果。 - ggorlen

27

只使用ES6方法

  1. Object.fromEntries

const log = console.log;

const map = new Map();
// undefined
map.set(`a`, 1);
// Map(1) {"a" => 1}
map.set(`b`, 2);
// Map(1) {"a" => 1, "b" => 2}
map.set(`c`, 3);
// Map(2) {"a" => 1, "b" => 2, "c" => 3}

// Object.fromEntries ✅
const obj = Object.fromEntries(map);

log(`\nobj`, obj);
// obj { a: 1, b: 2, c: 3 }

  1. ...spread解构赋值(destructuring assignment)

const log = console.log;

const map = new Map();
// undefined
map.set(`a`, 1);
// Map(1) {"a" => 1}
map.set(`b`, 2);
// Map(1) {"a" => 1, "b" => 2}
map.set(`c`, 3);
// Map(2) {"a" => 1, "b" => 2, "c" => 3}

const autoConvertMapToObject = (map) => {
  const obj = {};
  for (const item of [...map]) {
    const [
      key,
      value
    ] = item;
    obj[key] = value;
  }
  return obj;
}

const obj = autoConvertMapToObject(map)

log(`\nobj`, obj);
// obj { a: 1, b: 2, c: 3 }

refs

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/fromEntries

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment

https://2ality.com/2015/08/es6-map-json.html


21

我希望这个函数已经足够自解释了。这就是我用来完成工作的方式。

/*
 * Turn the map<String, Object> to an Object so it can be converted to JSON
 */
function mapToObj(inputMap) {
    let obj = {};

    inputMap.forEach(function(value, key){
        obj[key] = value
    });

    return obj;
}


JSON.stringify(returnedObject)

ES6 - 实现:mapToObj(inputMap) { const obj = {};inputMap.forEach((value, key) =>{ obj[key] = value; }); return obj; } - Tejashree

15
你可以循环地遍历map和它的键,并将值赋给它们。
function createPaths(aliases, propName, path) {
    aliases.set(propName, path);
}

var map = new Map(),
    object = {};

createPaths(map, 'paths.aliases.server.entry', 'src/test');
createPaths(map, 'paths.aliases.dist.entry', 'dist/test');

map.forEach((value, key) => {
    var keys = key.split('.'),
        last = keys.pop();
    keys.reduce((r, a) => r[a] = r[a] || {}, object)[last] = value;
});

console.log(object);


2
不要忘记添加 JSON.stringify(object)!(原帖作者想要一个 JSON 对象...) - evolutionxbox
4
没有JSON对象,只有符合JavaScript对象表示法的字符串。我认为stringify不是OP的问题。 - Nina Scholz

2

另一种方法。我很好奇哪种方法的性能更好,但是jsPerf已经崩溃了 :(。

var obj = {};

function createPaths(map, path, value)
{
 if(typeof path === "string") path = path.split(".");
 
 if(path.length == 1)
 {
  map[path[0]] = value;
  return;
 }
 else
 {
  if(!(path[0] in map)) map[path[0]] = {};
  return createPaths(map[path[0]], path.slice(1), value);
 }
}

createPaths(obj, 'paths.aliases.server.entry', 'src/test');
createPaths(obj, 'paths.aliases.dist.entry', 'dist/test');

console.log(obj);

不使用递归:

var obj = {};

function createPaths(map, path, value)
{
    var map = map;
    var path = path.split(".");
    for(var i = 0, numPath = path.length - 1; i < numPath; ++i)
    {
        if(!(path[i] in map)) map[path[i]] = {};
        map = map[path[i]];
    }
    map[path[i]] = value;
}

createPaths(obj, 'paths.aliases.server.entry', 'src/test');
createPaths(obj, 'paths.aliases.dist.entry', 'dist/test');
createPaths(obj, 'paths.aliases.dist.dingo', 'dist/test');
createPaths(obj, 'paths.bingo.dist.entry', 'dist/test');

console.log(obj);

var obj = {};

function createPaths(map, path, value)
{
    var map = map;
    var path = path.split(".");
    
    while(path.length > 1)
    {
        map = map[path[0]] = map[path.shift()] || {};
    }
    
    map[path.shift()] = value;
  
}

createPaths(obj, 'paths.aliases.server.entry', 'src/test');
createPaths(obj, 'paths.aliases.dist.entry', 'dist/test');
createPaths(obj, 'paths.aliases.dist.dingo', 'dist/test');
createPaths(obj, 'paths.bingo.dist.entry', 'dist/test');

console.log(obj);


jsPerf已经宕机了几周。 - evolutionxbox
2
在我的控制台中使用console.time,你的代码平均用时 0.023毫秒,而被接受的答案则平均用时 0.137毫秒 - evolutionxbox
如果用顺序代码替换递归(可能需要更多的代码行),它很可能会再次运行得更快。较少的代码并不一定意味着更快。 :-) - RobG
@RobG 很有道理。这些都是非常简单的性能测试。每个测试都进行了大约20次“运行”。 - evolutionxbox
@RobG:我知道,但递归太酷了。:P 我添加了一个没有递归的例子。 - IMTheNachoMan

1
var items = {1:"apple",2:"orange",3:"pineapple"};
let map = new Map(Object.entries(items)); //object to map
console.log(map);
const obj = new Object();
map.forEach((value,key)=> obj[key]=value);  // map to object
console.log(obj);

这两个问题已经被现有的答案覆盖了,我认为是吗? - General Grievance

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接