Array.fill() is pretty useful when you need to create an array with some default values.
For example:
const numbers = Array(5).fill(0);
console.log(numbers);
// [0, 0, 0, 0, 0]
Nothing unusual there.
But things get a bit confusing when you use it with objects.
Say you want three tasks, all initially incomplete:
const tasks = Array(3).fill({ done: false });
tasks[0].done = true;
console.log(tasks);
You might expect:
[
{ done: true },
{ done: false },
{ done: false }
]
But the actual result is:
[
{ done: true },
{ done: true },
{ done: true }
]
The reason is that fill() doesn't create a new object for each position.
It puts the same object reference into every slot.
You can check that with:
console.log(tasks[0] === tasks[1]);
// true
So changing a property through one array element also affects the others.
If you need separate objects, Array.from() works better here:
const tasks = Array.from(
{ length: 3 },
() => ({ done: false })
);
tasks[0].done = true;
console.log(tasks);
Now you get:
[
{ done: true },
{ done: false },
{ done: false }
]
Each call to the callback creates a new object.
The same issue can happen with nested arrays:
const grid = Array(3).fill(Array(3).fill(0));
grid[0][0] = 1;
console.log(grid);
// [[1, 0, 0], [1, 0, 0], [1, 0, 0]]
A better way to create that grid is:
const grid = Array.from(
{ length: 3 },
() => Array(3).fill(0)
);
Using fill() with numbers, strings, or booleans is fine. Just be careful when the value is an object or array.
It's a small detail, but it can cause some confusing bugs if you don't notice it.
Top comments (0)