caiogondim / fast-memoize.js

:rabbit2: Fastest possible memoization library

Home Page:https://npm.im/fast-memoize

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

JSON.stringify doesn't preserve object equivalence

chocolateboy opened this issue · comments

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.

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

@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

@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"}'

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

@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.

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

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.

@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).