Proposal: add an option to omit prototype of objects created by JSON.parse()
From: 段垚 (mailto:duanyao at ustc.edu) Date: 28 September 2016 at 16:36:52
[I]mplementors warn that mutating prototype causes "performance hazards".
You don't actually need to mutate any prototypes to get prototypeless
objects out of JSON.parse
- the reviver function is allowed to
return a new object instead, so you can create a fresh one with the
correct prototype. For example:
JSON.parse(string, function(k, v) {
if (v && typeof v === 'object' && !Array.isArray(v)) {
return Object.assign(Object.create(null), v);
}
return v;
});
How about adding an option to omit prototype of objects created by JSON.parse()?
JSON.parse(str, { noPrototype: true });
While you can achieve the appropriate result already without extra language support, I think this particular situation is common enough that such an option might be a good idea.
How would you expect this new parameter to interact with the existing
second parameter to JSON.parse
, the reviver function? I'd suggest
that the cleanest way to add the options would be for the second
parameter to be either an object or function, like this:
JSON.parse(str, someFunc);
// equivalent to
JSON.parse(str, {reviver: someFunc});
Another approach would be to use two separate optional parameters,
i.e., JSON.parse(text[, reviver][, options])
, but generally that
style is very messy.
在 2016/9/28 22:59, Danielle McLean 写道:
From: 段垚 (mailto:duanyao at ustc.edu) Date: 28 September 2016 at 16:36:52
[I]mplementors warn that mutating prototype causes "performance hazards". You don't actually need to mutate any prototypes to get prototypeless objects out of
JSON.parse
- the reviver function is allowed to return a new object instead, so you can create a fresh one with the correct prototype. For example:
JSON.parse(string, function(k, v) { if (v && typeof v === 'object' && !Array.isArray(v)) { return Object.assign(Object.create(null), v); } return v; });
Yes, but creating a copy also has performance penalty. This proposal is made for performance.
How about adding an option to omit prototype of objects created by JSON.parse()?
JSON.parse(str, { noPrototype: true }); While you can achieve the appropriate result already without extra language support, I think this particular situation is common enough that such an option might be a good idea.
How would you expect this new parameter to interact with the existing second parameter to
JSON.parse
, the reviver function? I'd suggest that the cleanest way to add the options would be for the second parameter to be either an object or function, like this:
JSON.parse(str, someFunc); // equivalent to JSON.parse(str, {reviver: someFunc});
Looks reasonable.
Maybe we can simply add another method, say
JSON.parseWithoutPrototype()
. This makes feature detection easier.
Have you ever encountered performance issue because of copying object on deserialization?
gist.github.com/Ginden/381448a17f50c7669b9a3693742e3a3d For me results are:
Simple JSON.parse, 100000 iterations: 39.594999999997526ms JSON.parse with copy, 100000 iterations: 184.5699999999997ms JSON.parse with proto change, 100000 iterations: 89.75500000000102ms
在 2016/9/29 0:04, Michał Wadas 写道:
Have you ever encountered performance issue because of copying object on deserialization?
Not yet.
gist.github.com/Ginden/381448a17f50c7669b9a3693742e3a3d For me results are:
Simple JSON.parse, 100000 iterations: 39.594999999997526ms JSON.parse with copy, 100000 iterations: 184.5699999999997ms JSON.parse with proto change, 100000 iterations: 89.75500000000102ms
Thanks for writing this test. I got similar result on Firefox; while on Chrome and Edge, there is not much difference between coping and changing proto .
However, it is not easy to messure overhead of GC after copy and the effect of proto change on property access performance.
Given that JSON.parse doesn't necessarily return an object, would the
noPrototype option would be ignored on e.g. JSON.parse('"some string"')
or JSON.parse('true')
?
From: Olivier Lalonde (mailto:olalonde at gmail.com) Date: 30 September 2016 at 07:21:10
Given that JSON.parse doesn't necessarily return an object, would the noPrototype option would be ignored on e.g.
JSON.parse('"some string"')
orJSON.parse('true')
?
The noPrototype option should set the behaviour whenever the parser encounters a JSON object (i.e., key-value pairs wrapped in curly braces). If the JSON text to be parsed does not contain any objects, then the option will have no effect. 'true', 'some string', and '[1,2,3,"four"]' are examples of JSON texts which would not be affected by the noPrototype option. (Note that although an array is a JavaScript object, it's not a JSON object.)
Conversely, if the JSON text to be parsed contains multiple objects -
for instance, JSON.parse('[{"first": 1}, {"second": 2}, {"third": 3}]', {noPrototype: true})
- then all of those objects should be
constructed with a null prototype.
var o = JSON.parse('{}'); Object.setPrototypeOf(o, null);
On Thu, Oct 6, 2016 at 12:50 PM, Rick Waldron <waldron.rick at gmail.com> wrote:
var o = JSON.parse('{}'); Object.setPrototypeOf(o, null);
That's not remotely correct, as it does nothing for anything other than the top object. (And it breaks things if the top-level value isn't an object.)
It is usually a bad practice to let a map-like object (an plain object used as a key-value map) have a prototype.
Objects created by JSON.parse() have a prototype by default, and we can get rid of them by:
JSON.parse(str, function(k, v) {
});
However, implementors warn that mutating prototype causes "performance hazards" [1].
How about adding an option to omit prototype of objects created by JSON.parse()?
E.g.:
JSON.parse(str, { noPrototype: true });
[1] developer.mozilla.org/en-US/docs/Web/JavaScript/The_performance_hazards_of__[[Prototype]]_mutation