Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Adding to an array in javascript via defineProperty - is there a better way?

The goal is to create a dynamic 'sum' row in a 2d javascript array. Here's the starting point:

var m = [[1,2,3], [4,5,6]];

We can add a third row thus:

Object.defineProperty(m, 2, { get: () => m[0].map((e, i)=> e + m[1][i]) })

So now our array is

[[1,2,3], [4,5,6], [5,7,9]]

It works! Setting m[0][0]=10 and we get

[[10,2,3], [4,5,6], [14,7,9]]

which is exactly what I want. m.length = 3 as expected, so the sum row is being treated as part of the array. JSON.stringify works as expected too. (I was a bit surprised it worked tbh).

My question is - is there a way of generating parts of a 2d array dependent on other parts without resorting to defineProperty? Is this something to avoid?

(Note - in my original question I had done the above, then changed m[2] to something else. The 'property' won over the array member, which lead to some confusion. This in itself may be a reason not to use the above method. Apolgies.)

like image 455
Party Ark Avatar asked Sep 16 '25 17:09

Party Ark


1 Answers

It works! I was a bit surprised it worked tbh.

Yes. Arrays are just objects with a special .length property, the indices are just normal properties. Which means you can make them setters if you want to.

Btw, you can improve on that by using this in the getter instead of always referring to m:

var thirdRowDescriptor = {
    enumerable: true,
    configurable: true,
    get() {
        return this[0].map((x, i) => x + this[1][i]);
    }
};
Object.defineProperty(m, 2, thirdRowDescriptor);
// or use the same descriptor on any other arrays

Is there a better way of generating parts of a 2d array dependent on other parts without resorting to defineProperty?

No, a getter created using Object.defineProperty seems to be exactly what you want. There are many other ways of dynamically generating arrays dependent on others, but none of them really makes it "part of" the outer array.

Is this something to avoid?

Possibly. I'm pretty sure it destroys performance of the outer array (to which you added the getter), as the engine cannot optimise the index access easily. However, if that's really just a two-column object to which you wanted to add one other column, this should not be a problem. Just don't do it on large arrays or arrays that are growing/shrinking dynamically. Maybe using a plain object (not an array) for the outer structure would be a better choice, if its structure is static anyway.

like image 122
Bergi Avatar answered Sep 18 '25 08:09

Bergi