4

Why does the following enumerate correctly?

var arr = [];
arr[0] = 'foo';
arr['1'] = 'bar';

arr.forEach(v => console.log(v)); // foo, bar

Both arr[1] and arr['1'] also work. Is this a feature of Array that strings corresponding to integers are mapped to their integer value?

Ben Aston
  • 53,718
  • 65
  • 205
  • 331

3 Answers3

2

It's due to the fact that arrays in Javascript are just objects with some dedicated syntactic sugar.

Compare:

var arr = [];
arr[0] = 'foo';
arr['1'] = 'bar';
console.log(arr['0']);
console.log(arr[1]);

... to:

var obj = {};
obj[0] = 'foo';
obj['1'] = 'bar';
console.log(obj['0']);
console.log(obj[1]);

Basically, Array is a type of Object, with array specific methods and non-enumerable properties, such as length, which can be instantiated with the dedicated shorthand syntax [ items... ]

The indices of an array are actually strings, just like all keys in any object, it works because referencing an object property using a number as a key will coerce that number into its string representation (in principle, that is. I assume most modern browsers have internally optimized this heavily).

Example:

var obj = {};
obj[1.5] = 'foo';
console.log('1.5' in obj);
console.log(obj[1.5]);

var arr = [];
arr[0.5] = 'foo';
console.log('0.5' in arr);
console.log(arr[0.5]);

arr[0] = 'bar';
arr[1] = 'baz';
console.log(arr.length);
console.log(Object.keys(arr));
Lennholm
  • 7,205
  • 1
  • 21
  • 30
  • 1
    @BenAston Maybe it was poorly phrased, but they are properties of the object and the keys of objects are always strings. However, it's *considered* to be an array index only if it is the string representation of a positive integer. – Lennholm Jul 05 '17 at 10:39
1

For those questions, It may be worth taking a look into the specification

Array objects give special treatment to a certain class of property names. A property name P (in the form of a String value) is an array index if and only if ToString(ToUint32(P)) is equal to P and ToUint32(P) is not equal to 2^(32)−1

Thus, because:

parseInt("1").toString() === "1"

"1" is a perfectly valid array index.

See http://www.ecma-international.org/ecma-262/5.1/#sec-15.4

EDIT: One might ask "What's with 1 (a number)", because parseInt(1).toString() is not equal to 1 (but "1", a string). I think the answer to this is the part "(in the form of a String value)", so I believe 1 is first interpreted as "1" before applying those rules.

SVSchmidt
  • 6,269
  • 2
  • 26
  • 37
1

Is this a feature of Array that strings corresponding to integers are mapped to their integer value?

No. Think of Arrays just like regular objects.

When accessing a property of an object using bracket notation - the property must be quoted.

eg: var someVar = { a:1, b:2 } - to access the value of property 'a' with bracket notation we write: someVar['a']

So it makes perfect sense to access array elements via quoted indexes.

That being said, it isn't necessary to quote the index - and that's because - as others have mentioned - the index is coerced into a string by the JavaScript engine through an implicit toString conversion

Danield
  • 121,619
  • 37
  • 226
  • 255
  • 1
    Thanks. I had it the wrong way around in my head - I thought arrays had integer indices. Instead they have *string* properties that correspond to the 32-bit integer subset of IEEE-754, exposed via the usual indexer (property access) syntax. – Ben Aston Jul 05 '17 at 11:12
  • "The way that Arrays differ from objects here is that quoting the index is not necessary " - Are you sure normal objects don't also have this behavior? `var o = {}; o[1] = 'foo'; o[1]; // foo` – Ben Aston Jul 05 '17 at 11:21