> const l = [1,2,3];
undefined
> l.a = l;
[ 1, 2, 3, a: [Circular] ]
> l === l.a
true
> l[-1] = 0;
0
> l
[ 1, 2, 3, a: [Circular], '-1': 0 ] > l = [1,2,3]
(3) [1, 2, 3]
> l[3] = 4
4
> l
(4) [1, 2, 3, 4]
> l[-1] = "eek"
"eek"
> l
(4) [1, 2, 3, 4, -1: "eek"]
So adding a 4 as a "key" is a proper array element; adding -1 is an object key. I'm struggling to see how anyone could think this is a good idea. Saying that they're objects is not reasonable. Objects don't need to do this (in most languages lists are objects, and they don't also do key-value pairs at the same time); they just decided to make them do this.> Saying that they're objects is not reasonable.
This is a fair point, in the alternate universe where JS objects have different semantics.
> in most languages lists are objects, and they don't also do key-value pairs at the same time
This is a dynamic language we're talking about. You are very welcome to think dynamic languages are inferior choices, an opinion that I personally would share, but that's a discussion for another time. In the context of JS, that behavior is neither unreasonable nor inconsistent.
>>> l = []
>>> l.x = "hello"
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'list' object has no attribute 'x'
Always adding arbitrary properties to an object is not a dynamic thing, it's just a bit silly. At best you could say it's a weak typing thing, but even then, it doesn't need to be. > const a = [1, 2];
> a[0]
1
> a[2]
undefined
> a[-1]
undefinedThis is similar to LISP, where you can build many kinds of structures out of cons cells, and you have certain families of functions that assume that the cons cells you pass in have certain kinds of structures, defining lists or trees or association lists etc.