Encoding symbol keys in JSON?

Alex Vincent ajvincent at gmail.com
Mon Nov 13 11:10:27 UTC 2017

In modern ECMAScript, objects can have symbols for property names instead
of strings.  This leads me to a problem in my es7-membrane project:  how do
I translate those symbol keys into JSON for a reusable file?  (I partially
answer my own question below.)

Consider the following code:

  const X = {};
  const two = Symbol("two");
  Reflect.defineProperty(X, "one", {value: 1, writable: true, enumerable:
true, configurable: true});
  Reflect.defineProperty(X, two,   {value: 2, writable: true, enumerable:
true, configurable: true});
  return JSON.stringify(Reflect.ownKeys(X));

In both Mozilla Firefox and Google Chrome, this returns ["one", null].  I
suppose this is part of the ECMAScript's latest standard. I do see
JSON.stringify has a "replacer" callback argument, and JSON.parse has a
"reviver" argument.  I presume that these are here to solve
encoding/decoding problems with JSON.  This may be the route I take...

At first, serializing shouldn't be a problem:  if I hit a symbol as a key,
I could use the replacer functionality to deliver a standard
JSON-serializable object.

But what if the ordering of keys is not guaranteed?  I'm referring
specifically to the case of a developer modifying X's properties in the
above snippet - say, by defining Symbol("three") as a key before the two
key.  Or worse, by defining a different Symbol("two") before the existing
two key?  I am not referring to the case of the developer modifying the
results from Result.ownKeys().

Now, all of a sudden, this little stringify problem has possibly morphed
into a diff/merge problem:  between yesterday's serialized JSON for ownKeys
and today's, someone has cleverly inserted a symbol where there was another
in the list of keys.  My code is supposed to infer today from yesterday's
generated JSON which property key belongs to which property value.  With
symbols - especially identically-keyed symbols - I could lose that
consistency if I'm not careful.

(Side note:  for es7-membrane, I faced a similar but easily solvable
problem, where Reflect.ownKeys(function() {}) returned different results in
different browsers - especially when the function passed into ownKeys had
additional properties.  In that case all the properties were strings, so I
just extracted the common set of string-named properties and put them at
the front of the keys list for consistency.)

I'm looking for advice - including the very real possibility that I'm
overthinking this or worrying too much about an edge case.

"The first step in confirming there is a bug in someone else's work is
confirming there are no bugs in your own."
-- Alexander J. Vincent, June 30, 2001
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20171113/d3f5966e/attachment.html>

More information about the es-discuss mailing list