Core-js: Map polyfill breaks JSON.stringify with replacer function

Created on 15 Dec 2015  路  11Comments  路  Source: zloirock/core-js

<html>
<body>
<script src="core.min.js"></script>
<script>
var myObject = {
  map: new Map([["en", "foo"]])
}

function replacer(name, val) {
  console.log(val);
  if ( val instanceof Map ) {
    return {"en": "foo"};
  } else {
    return val; // return as is
  }
};

var json = JSON.stringify(myObject, replacer, 4);
console.log(json);
</script>
</body>
</html>

The output is:

 Object { map=Map}
[["en", "foo"]]
["en", "foo"]
en
foo
{
    "map": [
        [
            "en",
            "foo"
        ]
    ]
}

Without core-js it is:

 Object { map=Map}
Map {}
foo
{
    "map": {
        "en": "foo"
    }
}
question

All 11 comments

Expected behavior. Stage 0 proposal.

I don't understand this. The replacer function is meant for taking action _before_ serializing to JSON, so it should receive the original value, in that case the Map object, which also happens when the polyfill is not active. I agree that a default JSON serialization for Map and Set is useful, but this is not what this issue is about.

Thanks for pointing me there. You're right, it is as expected, but I have to say I find this algorithm really a bit unintuitive and actually dangerous since it may break your code at any time if someone decides to put a toJSON function to a prototype whose transformation you have handled manually before. Apart from that, with this stage 0 proposal and the algorithm you linked to there is no way to detect that a value had been a Map, since it is just a nested array now. Am I missing something? Do you agree or disagree and do you think I should raise this issue somewhere?

@neothemachine why do you need to know if it's a Map or an array of entries? Any issues caused by serializing the Map would be present in the entries array (namely, a key or value you couldn't serialize).

Well, because I want to serialize Map's as simple objects because I know that they have strings as keys.

@neothemachine if you have a subset of Map and want special behavior for it then you absolutely can't rely on toJSON here. I'd recommend either just using a normal object, or (if you want the Map API), use a subclass of Map that only allows string keys and has a custom toJSON implementation on its prototype.

@ljharb Ok I accept that, but I still don't like the general approach of how toJSON works together with stringify (so my concern is not related to core-js at all in the end). It seems a bit strange to me that the encoding in one specific JSON format is so tightly coupled to the model object. What if I have two different JSON formats and want to serialize my object in both? Then I would have to recreate the whole object hierarchy with the different set of Map subclasses just to get the encoding right. Typically the encoder part is separate and I thought this is exactly what the replacer function is good for. I think separation of concerns is not really solved well here, but it works for the majority of cases I guess.

It seems the proposal has been rejected.

@larsgw so it was removed from core-js@3.

Right, sorry. I still saw the behaviour in @babel/polyfill, which I thought was up to date.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

mryellow picture mryellow  路  6Comments

devongovett picture devongovett  路  4Comments

straczowski picture straczowski  路  4Comments

blondie63 picture blondie63  路  4Comments

ajbowler picture ajbowler  路  3Comments