为啥 Array.prototype.reduce() 不接受 Map 对象作为初始值?

Posted

技术标签:

【中文标题】为啥 Array.prototype.reduce() 不接受 Map 对象作为初始值?【英文标题】:Why wouldn't Array.prototype.reduce() accept a Map object as an initial value?为什么 Array.prototype.reduce() 不接受 Map 对象作为初始值? 【发布时间】:2016-08-23 20:36:51 【问题描述】:

好的,这个问题被搁置了,原因如下;

“这个问题是由无法再重现的问题或简单的印刷错误引起的。”

我只是想确认问题在 *** 沙箱、repl.it sanbox 甚至 Firefox 控制台上仍然存在,这肯定不是错字。将代码复制粘贴到 Firefox 控制台,它将无法正常工作。

我一直在尝试根据一个特定属性对 Map 对象中的多个对象进行排序。我更喜欢使用箭头函数和数组方法。似乎Array.prototype.reduce() 不接受新的 Map 对象作为开始的初始参数。我也不明白的是,虽然 Map 对象不会被填充,但最后它的大小显示了正确的值,就好像它确实一样。谁能告诉我这里发生了什么..?为什么 Map 对象在大小显示为 3 时看起来是空的。

var myClients = 
    'cccc':  newValue: 'test three', timeTest: 3 ,
    'bbbb':  newValue: 'test two', timeTest: 2 ,
    'aaaa':  newValue: 'test one', timeTest: 1 
;

var mc = Object.keys(myClients)
    .sort((p,c) => myClients[p].timeTest <= myClients[c].timeTest ? -1 : 1)
    .reduce((p,c) => p.set(c, myClients[c]); console.log(p.size); return p, new Map());

console.log(mc, mc.size);

你可以试试here。

好的,我已经接受了一些答案,但即使在 stackjoverflow 沙箱中也无法正确显示。检查一下

var myClients = 
    'cccc': 
      newValue: 'test three',
      timeTest: 3
    ,
    'bbbb': 
      newValue: 'test two',
      timeTest: 2
    ,
    'aaaa': 
      newValue: 'test one',
      timeTest: 1
    
  ,
  mc = Object.keys(myClients)
    .sort((p, c) => myClients[p].timeTest <= myClients[c].timeTest ? -1 : 1)
    .reduce((p, c) => 
      p.set(c, myClients[c]);
      console.log(p.size);
      return p
    , new Map());
document.write("<pre>" + JSON.stringify(mc, null, 2) + "</pre>");

【问题讨论】:

我无法重现,您的代码工作正常。究竟是什么意外? @Bergi 我依赖 repl.it 控制台.. 这似乎是问题所在。 :( @Bergi 似乎除了 Chrome 控制台之外,它在任何地方都不起作用。例如,Firefox 无法正常运行。所以它是可重现的,当然不是错字。 【参考方案1】:

不要相信console.log 进行调试;实际使用the debugger 会好得多,这样您就可以自己检查对象了。

在这种情况下,您的代码似乎可以正常工作;运行 sn-p 并查看浏览器的控制台,您应该会看到您所期望的。 repl.it 对console.log 的实现似乎只是将Map 的所有实例记录为""

var myClients = 
    'cccc': 
      newValue: 'test three',
      timeTest: 3
    ,
    'bbbb': 
      newValue: 'test two',
      timeTest: 2
    ,
    'aaaa': 
      newValue: 'test one',
      timeTest: 1
    
  ,
  mc = Object.keys(myClients).sort((p, c) => myClients[p].timeTest <= myClients[c].timeTest ? -1 : 1).reduce((p, c) => 
    p.set(c, myClients[c]);
    console.log(p.size);
    return p
  , new Map());
console.log(mc, mc.size);

【讨论】:

我可以发誓我已经用控制台检查过了。看起来我没有:) 然而......它也恰好没有正确显示在***沙箱中。为什么会发生这种情况..? @Redu 我已经更新了我的答案,描述了如何使地图的内容可见。【参考方案2】:

您的代码非常好,这是一个失败的repl.it 控制台。

您可以通过按键访问 Map 条目来检查您的代码是否正确:

mc.has('cccc') // true
mc.get('cccc') //  newValue: 'test three', timeTest: 3 

更新:序列化地图

repl.it 和 *** 的 sn-p 中 Map 看起来为空的原因是两者都将其转换为字符串。

为了得到一个 Map 的有意义的字符串表示,你应该覆盖它的 toString 方法,像这样:

class SerializableMap extends Map 
  toString() 
    const res = ;
    for (let entry of this.entries()) 
      res[entry[0]] = entry[1];
    
    return JSON.stringify(res);
  

var myClients = 
    'cccc':  newValue: 'test three', timeTest: 3 ,
    'bbbb':  newValue: 'test two', timeTest: 2 ,
    'aaaa':  newValue: 'test one', timeTest: 1 
;

class SerializableMap extends Map 
  toString() 
    const res = ;
    for (let entry of this.entries()) 
      res[entry[0]] = entry[1];
    
    return JSON.stringify(res);
  


var mc = Object.keys(myClients)
    .sort((p,c) => myClients[p].timeTest <= myClients[c].timeTest ? -1 : 1)
    .reduce((p,c) => p.set(c, myClients[c]); console.log(p.size); return p, new SerializableMap());

document.write(mc)

现在您可以轻松查看地图的状态。

【讨论】:

感谢 Roman 解开这个谜团。赞赏。所以你说在某些沙箱中 Map 对象的 toString 方法在某种程度上是错误的。 似乎它也不会显示在 Firefox 控制台中。

以上是关于为啥 Array.prototype.reduce() 不接受 Map 对象作为初始值?的主要内容,如果未能解决你的问题,请参考以下文章

Array.prototype.reduce()

Array.prototype.reduce 的理解与实现

Using Array.prototype.reduce() to Reduce Conceptual Boilerplate for Problems on Arrays

如何正确使用 TypeScript 和 Array.prototype.reduce?

前端开发Array.prototype.reduce()的详细解析&使用

Array数组语法系列: Array.prototype.reduce