Array.isArray(new Proxy([], {})) should be false (Bug 1096753)

Allen Wirfs-Brock allen at wirfs-brock.com
Thu Nov 13 14:56:42 PST 2014


On Nov 13, 2014, at 1:35 PM, Tom Van Cutsem wrote:

> 2014-11-13 20:31 GMT+01:00 Allen Wirfs-Brock <allen at wirfs-brock.com>:
> 
> 3) Proxies. Should Array.isArray treat proxy instances specially? To answer this question we need to think about what a ES programmer actually thinks Array.isArray means? The meaning that ES5 established is that Array.isArray returning true means that the object observably maintains the array `length` invariant.
> 
> Is the `length` invariant really the dominant meaning JS developers attribute to Array.isArray? I think to most developers Array.isArray(obj) returning true means that it's safe to call the array utilities (map, forEach, ...) on obj, not so much that obj.length is special.

I agree that what JS programs think Array.isArray means is the key issue here.  But if "safe to call array utilities" is what it means then the world is really confused.   I guess it may come down to what "safe" means in that statement. More than any other built-in class the Array prototype methods are specified to be generic to any object.

All of the Array.prototype methods work just fine with `a` defined as:
```js
var a={0:"zero", 1:"one", length: 2};
```
but `Array.isArray(a)` answers false.

Conversely:
```js
var b=Object.freeze(["zero", "one"]);
b.sort();
```
is going to throw, even though `Array.isArray(b)` answers true.

> 
> My intuition is that Array.isArray is often used to branch based on whether code received just one versus a collection of values. E.g. a function may take a single parameter that can be bound to either a single value or a collection of values, and treat a collection of values differently. In fact, that is essentially what Array.prototype.concat does: if the argument is an array, splice its values, otherwise, don't splice. This has nothing to do with `length` magic. The same goes for JSON.stringify (serialize as "[]" vs "{}").

Well, Array.isArray was new in ES5 so it's legacy only goes back that far. 

We might redefine Array.isArray to be based upon testing for @@isConcatSpreadable but that potentially would give different results for legacy uses that did __proto__ hacking such as I mentioned in my previous mote.

> 
> Now, if we take the meaning of Array.isArray to be "supports the Array.prototype utility methods", a proxy-for-array may of course expose a totally different API, leading a client that expects to be able to use the Array.prototype methods to fail. But this foregoes the fact that for virtually all practical use cases of proxies, proxy authors will not do this. They want to be able to wrap objects, intercept some things, but mostly faithfully forward those operations to the wrapped target. It would be rare for a proxy to change the API of the thing it wraps. Indeed, the whole point of proxies is to be able to intercept operations without modifying client code.

Certainly if you use a proxy to define a virtual object, to self-host, spec-defined exotic objects or to implement DOM objects you just aren't transparently wrapping the target object...

I think at the root of this is that many JS programmer don't really understand what is (or isn't special about Array instances and that Array.isArray may have just added to the confusion.  

Allen

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20141113/c7b1dd6d/attachment-0001.html>


More information about the es-discuss mailing list