Fun with Array.prototype.fill()

smlka

Andrey Smolko

Posted on June 25, 2024

Fun with Array.prototype.fill()

Recently, I came across the following code snippet:

const arr = new Array(2).fill([])
arr[0].push(1)
arr[0] === arr[1] // true or false?
Enter fullscreen mode Exit fullscreen mode

The correct answer is true.
Both elements at indexes 0 and 1 contain the same mutable value - empty array which was passed as an argument the the method.
See the description from the ECMAScript specification:

Image description

Array.prototype.fill() expects in its first parameter an already defined value and then just set the same value as "number"-keyed property values (step 11b).

This definitely sounds like a challenge for JS geeks. Is it possible to use Array.prototype.fill() in such a way that each element in the resulting array has its own empty array?
Something like that:

const arr = new Array(2).fill([])
arr[0].push(1)
arr[0] === arr[1] // false
arr[0].length //1
arr[1].length //0
Enter fullscreen mode Exit fullscreen mode

To achieve this, I’d use the insight provided by step 11b from the specification:

b. Perform ? Set(O, Pk, value, true).

That statement is straightforward: it sets the value (value) of a specific property key (Pk) of an object (O). JavaScript has a feature that can intercept and redefine fundamental operations for that object. It's called a Proxy!

Let's use a Proxy object and redefine an array set operation to solve our challenge:

const handler = {
    set(obj, prop, value) {
    //assign a new "instance" of empty array to the properties
    obj[prop] = [...value]    
    return true
  },
}
// Proxy cracks the challenge!
const arr = [...new Proxy(Array(2), handler).fill([])];
arr[0].push(1)
arr[0] === arr[1] // false
arr[0].length //1
arr[1].length //0
Enter fullscreen mode Exit fullscreen mode

Solved!

💖 💪 🙅 🚩
smlka
Andrey Smolko

Posted on June 25, 2024

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related