4

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.)

3
  • 1
    There must be more code that you are not showing. Somewhere the function is being executed. Commented Sep 17, 2016 at 9:59
  • 1
    You are calling m[2]=m[2]() somewhere before having: [ [ 1, 2, 3 ], [ 4, 5, 6 ], [ 5, 7, 9 ] ] Commented Sep 17, 2016 at 10:06
  • I just ran OP's code as provided. There is no need to call m[2]=m[2]() as Marcs says. It actually throws an error if you try to call m[2]=m[2](). Getters don't need to be called before they work Commented Dec 13, 2022 at 22:24

2 Answers 2

3

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.

Sign up to request clarification or add additional context in comments.

Comments

0

See result below: m[2] is a function. And the result isn't the same as you said.

m = [[1, 2, 3], [4, 5, 7]];
m[2] = () => m[0].map((e, i) => e + m[1][i]);

console.log(m);
console.log(Array.isArray(m[2]))
console.log(m[2]());
console.log(typeof(m[2]));

1 Comment

apolgies, you're right, i missed something, I'll rewrite the question

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.