Description
I'm not quite sure how to motivate this problem without describing 3 different phenomena at once so please bear with me:
- JSON.stringify does not work on Proxy objects (it fails with "Illegal Access" exception).
- So I've been using Crockford's json2.js when I need to JSON-serialize Proxy objects. This works fine except if I have a Proxy to an Array (or to an object with an embedded Array), the generated JSON is just an object with numeric keys, not an Array (literally, more like
{ "0": 'foo', "1": 'bar' }
instead of['foo', 'bar']
. - The second thing is because the test json2.js uses to determine whether something is an array is the
Object.prototype.toString.apply(candidate) === '[object Array]'
test. Proxy to Array returns[object Object]
.
It's the third of these that I think is arguably a bug in the proxy implementation (or I'd like to know why not, and how to work around it!).
magi@ubuntu ~/src> node --harmony
> require('harmony-reflect')
> JSON2 = require('./json2')
> a = ['foo','bar']
[ 'foo', 'bar' ]
> p = Proxy(a, {})
{ '0': 'foo',
'1': 'bar' }
> JSON.stringify(p)
illegal access
> JSON2.stringify(p)
'{"0":"foo","1":"bar"}'
Note there that the REPL's display of p
shows it as an object with numeric keys, as I described in (2) above. So not only json2.js but also util.inspect
(which the REPL uses) is treating p
as a general Object, not as an Array.
Also note that the builtin JSON.stringify
on a proxy just fails with "illegal access".
Here's the full battery of tests I can think of for whether something is an array (all of these return true for a, but mostly not for p):
> a instanceof Array
true
> Array.isArray(a)
true
> require('util').isArray(a)
true
> Object.prototype.toString.apply(a)
'[object Array]'
> p instanceof Array
true
> Array.isArray(p)
false
> require('util').isArray(p)
false
> Object.prototype.toString.apply(p)
'[object Object]'
So the instanceof
test works on the proxy, but all the other tests fail. And a lot of code out there wants to use the Object.prototype.toString test. Now, the reasons for using the Object.prototype.toString test instead of the instanceof test might not be relevant to Node (namely, browser-side stuff with multiple frames or iframes). But is there any hope that Object.prototype.toString should be returning Array and not Object for arrays?
Some further details:
- I was hoping that (1) would be fixed in more recent versions of Node, from https://chromiumcodereview.appspot.com/11312063 and https://code.google.com/p/v8/source/detail?r=12851.
- (I don't know how to tell from Chromium or V8 bug reports what V8 version a fix goes into, but from the general timeframe of the fix, I was hoping this would be in V8 3.15.)
- I just tried building Node.js from source, which currently comes with V8 3.16.17, and JSON.stringify(proxy) still fails as shown below.