new Array(1) => [empty title x 1]
Tags: javascript, arrays, deepdive
Published: 2019-01-04 18:52:46

---
title: new Array(1) => [empty title x 1]
published: true
description: A deep-dive into why a `new Array` yields such unexpected results
tags: javascript, arrays, deepdive
---

Imagine it's been a rough week.

Finally, it's time to refill our weekly chocolate supply. As usual, we're using JavaScript to fill our chocolate supply.

In pseudocode, "a box of 21 of the same kind of chocolate" would be something like:

> 1. Get a box.
> 2. Make sure the box has enough slots for 21 chocolates.
> 3. As long as there are still empty slots:
>     * Get a chocolate from the giant bag of chocolates.
>     * Put one chocolate into the slot you're looking at.
>     * Move on to the next slot.

Pretty reasonable, right? Let's give it a shot!

<i>(Note: all snippets should be runnable as-is in a repl or console as desired, just by copy-pasting if you like.)</i>

## Attempt 1: `.map`

For a first swing, maybe we'd try `map`:

```javascript
let chocolate = {
    kind: 'dark',
    filling: 'raspberry ganache'
};

// Prep our box and make sure it has 21 slots
let weeklyChocolateSupplyBox = new Array(21);

// Put one chocolate into every slot
weeklyChocolateSupplyBox.map(_emptySlot => chocolate);
```

(If you're wondering about the underscore (i.e., `_emptySlot`), that means the variable is either unimportant or unused. Some languages enforce that as a rule, like Elixir; here, it's purely convention.)

So far, so good: we make an array with 21 slots, we loop over it with `map`, and put a chocolate in at each slot.

<p align="center"><small><i>We actually put the exact same chocolate in each slot, which would be less than ideal in the real world &mdash; any changes to any one chocolate would effect EVERY chocolate, as they are all this way the same chocolate.<i></small></p>

> `(╯°□°）╯︵ [Ɛ x ʎʇdɯǝ]`

Maybe not too surprisingly, it doesn't work. Instead of an array containing 21 identical chocolates, if you run that snippet in a console, you'll get something like: `[empty × 21]`.

Less than ideal, to say the least.

## Attempt 2: `for (let index ... )`

While I love using the various array methods when I can &mdash; e.g., `forEach`, `filter`, `map`, etc., I've found that since I learned C-style `for` loops first, I often refer back to them when things aren't working. Similarly, as a sanity check, I often log out something before and after the loop, so I can make sure nothing truly whacky is going on like being in the wrong file, etc.

At the end of the day, a loop is a loop, use what is clearest to you and others.

So, we try again!

```javascript
// same as before
chocolate = {
    kind: 'dark',
    filling: 'raspberry ganache'
};

// assign the variable a whole new array to reset.
weeklyChocolateSupplyBox = new Array(21);

console.log('before loop');
for (let index = 0; index < weeklyChocolateSupplyBox.length; index += 1) {
    console.log('loop number %d', index);
    weeklyChocolateSupplyBox[index] = chocolate;
}

console.log(weeklyChocolateSupplyBox);
console.log('after loop');
```

This time, we succeed. We have a box with 21 chocolates in it, as desired! Awesome.

## Attempt 3: `for ... of`

Say that I didn't use an old-school `for` loop: say I had gone ahead with a `for ... of` loop &mdash; after all, I want to loop over this array and put things into it, right? This way, too, I can eliminate needing to increment the index myself, and not worry about if I forgot a condition or something. Great!

So let's write the code, and use a `for ... of` loop instead. We start off the same as before, and sketch out the skeleton of our `for` loop.

```javascript
chocolate = {
    kind: 'dark',
    filling: 'raspberry ganache'
};

// assign the variable a whole new array to reset.
weeklyChocolateSupplyBox = new Array(21);

console.log('before loop');
for (let emptySlot of weeklyChocolateSupplyBox) {
    console.log('emptySlot', emptySlot);
    // Put a chocolate into our emptySlot
}
console.log('after loop');
```

...but what goes inside the loop? We have an `emptySlot` &mdash; but _no_ way to add a chocolate to it. If we ran this now, we'd just see `emptySlot undefined` logged out 21 times. Not helpful.

## Attempt 4: `for ... in`

In JavaScript, everything is an object. Arrays are too &mdash; in particular, are an object created by the `Array` constructor. By definition, they have a `length` property, and numeric, ordered keys.

There's another kind of `for` loop we haven't tried: `for ... in`, which loops over the properties of an object. For something like an object literal, it loops over the property names; for an array, it loops over the indices. A little weird, but if you think about it, that seems sort of reasonable &mdash; we can use both a string key and an array index to set the value, and then later access that value by the key, right?

```javascript
const dog = { name: 'Simon', age: 13, weight: 50 };
const someNumbers = [3, 1, 4];
for (let key in dog) {
    console.log('dog key', key); // 'name', then 'age', then 'weight'
    console.log('dog value', dog[key]); // 'Simon', then 13, then 50
}

for (let key in someNumbers) {
    console.log('someNumbers key', key); // '0', then '1', then '2'
    console.log('someNumbers value', someNumbers[key]); // 3, then 1, then 4
}
```

Okay, cool, nothing too interesting there, except for maybe being able to do that with arrays as well.

So, let's try the chocolate experiment again. The normal `for` loop worked &mdash; let's try the same thing but with a `for ... in` loop, and we can use the index to add it to the array like before.

```javascript
chocolate = {
    kind: 'dark',
    filling: 'raspberry ganache'
};

// assign the variable a whole new array to reset.
weeklyChocolateSupplyBox = new Array(21);

console.log('before loop');
for (let emptySlotIndex in weeklyChocolateSupplyBox) {
    console.log('emptySlotIndex', emptySlotIndex);
    weeklyChocolateSupplyBox[emptySlotIndex] = chocolate;
}
console.log('after loop');
```

This time, we see `before loop` and `after loop`, and ... literally nothing else.

## What's the difference?

So, we tried a number of things:
  * `map`: failed -- did nothing
  * `for ... of` loop: failed -- no way to add a chocolate
  * `for ... in` loop: failed -- never even looped!
  * basic `for` loop: worked!

None of this answers the question, though: why does a `for` loop work and the other options fail, with `for ... in` never looping?

The answer lies in the specification of JavaScript itself.

The Array constructor _does_ create an `Array` object and set its `length` to be the (single, numeric) value given<sup><a href="#foot_1">1</a></sup>.

What it does _not_ do, though, is set the indices (which are just keys, remember, which happen to be numbers) on the array object.

```javascript
// This is about what happens:
const newArray = {
    length: 2
};

// NOT this:
const badNewArray = {
    length: 2,
    '0': undefined,
    '1': undefined
};
```

If you've ever tried to remove something from an object &mdash; truly get rid of it, not just give it an `undefined` value, but remove the property _entirely_ &mdash; you know that `chocolate['filling'] = undefined` won't cut it. The property will still be there, just with `undefined` as its value.

To remove a property, you have to `delete` it: `delete chocolate['filling'];`. After that, if you inspect the object, there will be _no_ key called `filling` present. If we looked at its keys, we would not see `filling` listed.

So, what happens if you `delete` an index from an array?

```javascript
const someOtherArray = ['value at 0', 'value at 1', 'value at 2'];

console.log(someOtherArray); // ["value at 0", "value at 1", "value at 2"]
console.log(someOtherArray.length); // => 3

delete someOtherArray[1];

console.log(someOtherArray.length); // => still 3
console.log(someOtherArray);
// Chrome:  ["value at 0", empty, "value at 2"]
// Firefox: ["value at 0", <1 empty slot>, "value at 2"]
// Safari:  ["value at 0", 2: "value at 2"]
```

Each browser shows you the same thing, just differently: an array with length three and only two things in it, at 0 and 2. There's nothing at index 1 anymore &mdash; because there is _no_ index 1. Each array still has a length of 3.

This explains why `for ... in` failed so badly: the `for ... in` loop works over the keys of an object: there were no keys (indices) for it to enumerate over. Similarly, if we had looped above, both before and after deleting the index, we would have gone into the loop 3 times before deleting the index, and twice after its deletion.

## A not-so-well-known symbol

Here's another clue: `[...new Array(3)]` does what we had probably originally expected &mdash; and gives us `[undefined, undefined, undefined]`.

The answer is **iterators**; specifically, the value of the `Symbol.iterator` on an object. (`Symbol`s are a JavaScript primitive whose value is unique, and are often used as identifiers &mdash; much like atoms in other languages.)

If an object has a `Symbol.iterator`, that object is iterABLE: it has an iterATOR, an object that adheres to the _iterator_ protocol. Iterators are very neat and _very_ powerful &mdash; they're the guts behind `async`, `await`, generators, promises, the spread operator, `for ... of`, etc; they allow for entering and exiting different execution contexts asynchronously.

For our purposes, though, it's enough to know that an iterator essentially keeps track of your place in a loop. Many JavaScript objects have a default iterator &mdash; arrays, as well as anything else that you can spread (use `...` as above).

In particular, the default iterator specification<sup><a href="#foot_2">2</a></sup> says something like:

>    * Start with `index = 0`.
>    * As long as `index` is less than `array.length`:
>        * `Yield` the value of `array[index]`
>        * Increment the index, `index += 1`
>        * Keep going

<p align="center"><small><i>Lots of other array methods use similar logic &mdash; e.g., <code>toString</code> uses <code>join</code>, which has a similar algorithm.</i></small></p>

What do you get when you access a property that isn't on an object? In some languages, it wouldn't compile at all; in JavaScript, however, you don't get an error, you just get `undefined` &mdash; which, of course, can also be the value if the key _is_ there.

```javascript
const withKeyAndUndefined = { apples: undefined, pears: 3 };
const withKeyAndValue = { apples: 12, pears: 99 };
const withoutKey = { pears: 74 };

console.log(withKeyAndUndefined['apples']); // => undefined
console.log(withKeyAndValue['apples']);     // => 12;
console.log(withoutKey['apples']);          // => undefined
```

As for `map` failing as well?

Well... The specification<sup><a href="#foot_3">3</a></sup> for `map` (and `forEach` and other similar methods) spells out that the callback given is _only_ executed for those values "which are not missing" &mdash; that is, non-empty slots or where the indices are defined (so, nowhere right after construction).

```javascript
const yetAnotherArray = new Array(5);

yetAnotherArray.map(
    value => {
        throw new Error('never gonna happen');
    }
).fill(
    null // now we put something in every spot
).map(value => {
    console.log('now, this will show "null": ', value);
    return value;
});
```

Meanwhile, our basic `for`-loop worked right off the bat: because _we_ were creating those indices by setting a value under that key, the same way I can do `const dog = {name: 'Simon'}; dog.favoriteFood = 'peanut butter';` without `favoriteFood` ever having been defined as being on the original object.

```javascript
const array = new Array(5);

for (let index = 0; index < array.length; index += 1) {
    // does 'index' exist? Yes! It's its own variable, after all
    console.log('index', index);
    console.log(`before: ${index} in array?`, index in array);
    array[index] = 'whee';
    console.log(`after: ${index} in array?`, index in array);
}
```

There is, conveniently, a method to `fill` an array with any value. We can use that here, too.

For a simple case, we can just do `new Array(5).fill(chocolate)`; for anything more complex, though, we need first to `fill` the array with something &mdash; anything, even `null` or `undefined`.

```javascript
weeklyChocolateSupplyBox = new Array(21).fill(chocolate);
console.log(weeklyChocolateSupplyBox);

const rangeFrom_1_to_10 = new Array(10).fill(null).map((_null,index) => index + 1);

console.log(rangeFrom_1_to_10);
```

Remember, though, that what we actually end up with here is 21 references to the same chocolate &mdash; if we melt _one_ chocolate, they all melt, as what we really did was put the same identical chocolate into every slot through some truly spectacular quantum confectionary. (Chocolate, however, seemed much more enjoyable than an array of strings or numbers.)

---

<ol>
    <li id="foot_1">
        <a href="https://www.ecma-international.org/ecma-262/6.0/#sec-array-len">
        Array constructor specification
        </a>
    </li>
    <li id="foot_2">
        <a href="https://www.ecma-international.org/ecma-262/6.0/#sec-%arrayiteratorprototype%.next">
        Iterator specification
        </a>
    </li>
    <li id="foot_3">
        <a href="https://www.ecma-international.org/ecma-262/6.0/#sec-array.prototype.map">
        <code>map</code> specification
        </a>
    </li>
</ol>