Why wouldn't Array.prototype.reduce() accept a

2019-07-25 12:32发布

问题:

OK this question was put on hold for the following reason;

"This question was caused by a problem that can no longer be reproduced or a simple typographical error. "

I just would like to confirm that the problem still exists as of now on stackoverflow sandbox, repl.it sanbox and even on firefox console and it is certainly not a typo. Copy paste the code to Firefox console and it will not work as it should.

I have been trying to sort several objects in a Map object according to one specific property. I prefer to use the arrow functions and array methods. It seems like Array.prototype.reduce() wouldn't accept a fresh Map object as an initial parameter to start with. What i also don't understand is, while the Map object wouldn't get populated, at the end it's size shows the correct value as if it does. Can anybody tell me what's happening here..? Why the Map object looks empty while it's size shows 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);

You may try it out here.

OK there have been answers which i have accepted but even in the stackjoverflow sandbox it wouldn't show properly. Check it up

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>");

回答1:

Your code is perfectly fine, it's a repl.it console that fails.

You can check that your code is correct by accessing a Map entries by key:

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

Update: serializing Map

The reason why Map looks empty in repl.it and Stackoverflow's snippet is that both are converting it to string.

In order to get meaningful string representation of a Map, you should overwrite its toString method, like so:

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)

Now you can easily see the state of your Map.



回答2:

Don't trust console.log for debugging; it's much better to actually use the debugger so you can inspect the objects yourself.

In this case, your code seems to work fine; run the snippet and look in your browser's console and you should see what you expect. repl.it's implementation of console.log just seems to log all instance of Map as "{}".

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);