Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JSON.stringify doesn't preserve object equivalence #22

Open
chocolateboy opened this issue Jan 26, 2017 · 10 comments
Open

JSON.stringify doesn't preserve object equivalence #22

chocolateboy opened this issue Jan 26, 2017 · 10 comments

Comments

@chocolateboy
Copy link

https://gist.github.com/chocolateboy/254b44382e6c34f8ce7e

@StarpTech
Copy link

This cannot happen if your args are only primitive values.

memoized('foo', 3, 'bar')

Your order is guaranteed when you contruct the object manually.

c = "bar"
a = { foo: c  }
b = 20
memoized({ key1: a, key2: b })

but yes if you pass a random generated object the order is not guaranteed.

@FlorianWendelborn
Copy link

FlorianWendelborn commented Jan 29, 2017

@StarpTech any source on "order being guaranteed" for Objects? AFAIK they may explicitly be random.

@NeoPhi
Copy link

NeoPhi commented Feb 5, 2017

@dodekeract ES6 defines the order in which the keys of an object are enumerated: http://www.2ality.com/2015/10/property-traversal-order-es6.html

@chocolateboy
Copy link
Author

@NeoPhi

For example, JSON.stringify(obj) will always produce the same result, as long as obj is created in the same manner.

I'd love to see a source for that statement (@rauschma?). The spec itself says otherwise:

An object is an unordered collection of zero or more name/value pairs

Either way, it doesn't resolve this issue:

$ node --version
v7.5.0
$ node
> JSON.stringify({ foo: "bar", baz: "quux" })
'{"foo":"bar","baz":"quux"}'
> JSON.stringify({ baz: "quux", foo: "bar" })
'{"baz":"quux","foo":"bar"}'

@planttheidea
Copy link
Collaborator

planttheidea commented Feb 5, 2017

The problem is that the traversal order discussed in that article is not for all object traversals period. There is no universal order expectation for how objects will display, however a majority of engines today will show them in the order in which they were added. This is not guaranteed by any means, but pretty much all mainstream browsers follow that paradigm for simplicity and performance reasons.

More details => http://stackoverflow.com/questions/5525795/does-javascript-guarantee-object-property-order/38218582#38218582

@NeoPhi
Copy link

NeoPhi commented Feb 5, 2017

@chocolateboy ES6 spec defines JSON.stringify (independent of the RFC) to use the same enumeration sequence, making the order guaranteed:
http://www.ecma-international.org/ecma-262/6.0/#sec-serializejsonobject

You'd need to use a custom serializer to make { foo: "bar", baz: "quux" } equal { baz: "quux", foo: "bar" } if JSON.stringify is used.

@NeoPhi
Copy link

NeoPhi commented Feb 5, 2017

@planttheidea That Stack Overflow link is talking about ES2015. ES2016 clarified the ordering for all cases to be the same.

@planttheidea
Copy link
Collaborator

Add how many browsers have actually implemented the spec? There is a practicality piece in here, as implementing a custom serializer instead of leveraging JSON.stringify as the default will cause a fairly substantial performance decrease.

Naturally you can do it for your specific application, but this to call the native browser implementation an issue may be too much.

@chocolateboy
Copy link
Author

@NeoPhi Interesting. Thanks for the link!

You'd need to use a custom serializer to make { foo: "bar", baz: "quux" } equal { baz: "quux", foo: "bar" } if JSON.stringify is used.

Well, yes. While this excursion is interesting, it doesn't address this issue (other than confirming it).

@cauefcr
Copy link

cauefcr commented Dec 6, 2020

https://www.npmjs.com/package/canonicalize this fixes this problem.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants