# This should not be happening

**URL:** <https://es.discourse.group/t/this-should-not-be-happening/1881>\
**Category:** 💡 Ideas\
**Created:** [December 24, 2023, 5:24pm UTC](https://es.discourse.group/t/this-should-not-be-happening/1881 "2023-12-24T17:24:14Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![jaroslav.tavgen](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/jaroslav.tavgen/32/2732_2.png) [@jaroslav.tavgen](https://es.discourse.group/u/jaroslav.tavgen)\
**Post date:** [December 24, 2023, 5:24pm UTC](https://es.discourse.group/t/this-should-not-be-happening/1881/1 "2023-12-24T17:24:14Z")

</div>

```javascript
let two_dimensional_array = [[1],[2]];
let array_clone = [...two_dimensional_array]
array_clone[0][0] = 3;
console.log(two_dimensional_array[0]); // [3]

```

When I use the spread operator I assume it COPIES the array. Either don't let me spread multidimensional arrays (put an error message) OR clone the array.

---

<div class="post-metadata">

**Author:** ![dmchurch](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/dmchurch/32/1962_2.png) [@dmchurch](https://es.discourse.group/u/dmchurch)\
**Post date:** [December 24, 2023, 8:35pm UTC](https://es.discourse.group/t/this-should-not-be-happening/1881/2 "2023-12-24T20:35:07Z")

</div>

The problem is, JS doesn't have multidimensional arrays in the way many other languages do! That's actually an array _of_ arrays, which isn't the same thing as a two-dimensional array. (If you're coming from a C-like language, think of this as "`int *two_dim_ar[1]`", not "`int two_dim_ar[1][1]`")

If you need multidimensional array semantics (rectangular shape, full cloning) I recommend making an indexer function, like so:

```js
const array_width = 1;
function indexFor(r, c) {
    return r * array_width + c;
}
let two_dimensional_array =
    [1,
     2];
let array_clone = [...two_dimensional_array]
array_clone[indexFor(0, 0)] = 3;
console.log(two_dimensonal_array[indexFor(0, 0)]); // 3

```

You can also extend `Array` to create yourself a multidimensional array class, using something like this:

```js
const array_width = 1;
class TwoDimensionalArray extends Array {
    indexFor(r, c) { return r * array_width + c }
    get(r, c) { return this[this.indexFor(r, c)]; }
    set(r, c, v) { return this[this.indexFor(r, c)] = v; }
    delete(r, c) { delete this[this.indexFor(r, c)]; }
}
let two_dimensional_array = TwoDimensionalArray.of(
    1,
    2
);
// using [...tda] always creates a base Array, but .slice(0) maintains the species:
let array_clone = two_dimensional_array.slice(0); 
array_clone.set(0, 0, 3);
console.log(two_dimensional_array.get(0, 0)); // 3

```

But of course, you probably want to be able to make arrays of different widths, and to be able to perform various operations on them while maintaining their widths, so make the array class a _family_ of classes instead:

```js
const TwoDimensionalArrayFactory = (array_width) => class extends Array {
    // all code remains the same as above
};
let two_dimensional_array = TwoDimensionalArrayFactory(1).of(
    1,
    2
);
// all remaining code the same

```

You could obviously do something to translate the array-of-arrays into true multidimensional array form, but if you need that, the exercise is left to the reader 🙂

One potential pitfall to be aware of: the `TwoDimensionalArrayFactory` above doesn't cache the dynamically created array classes, so `instanceof` checks like this will fail:

```js
const tda = TwoDimensionalArrayFactory(1).of(1, 2);
console.log(tda instanceof TwoDimensionalArrayFactory(1)); // false

```

instead, modify the factory to cache each width, or store the created class at the call site:

```js
const Width1Array = TwoDimensionalArrayFactory(1);
const w1a = Width1Array.of(1, 2);
console.log(w1a instanceof Width1Array); // true

```

---

<div class="post-metadata">

**Author:** ![boutell](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/boutell/32/1971_2.png) [@boutell](https://es.discourse.group/u/boutell)\
**Post date:** [January 3, 2024, 1:31pm UTC](https://es.discourse.group/t/this-should-not-be-happening/1881/3 "2024-01-03T13:31:40Z")

</div>

JavaScript also now has structuredClone which can be your alternative to the spread operator here:

```javascript
let two_dimensional_array = [[1],[2]];
let array_clone = structuredClone(two_dimensional_array);
array_clone[0][0] = 3;
console.log(two_dimensional_array[0]); // [1]

```

---

<div class="post-metadata">

**Author:** ![dmchurch](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/dmchurch/32/1962_2.png) [@dmchurch](https://es.discourse.group/u/dmchurch)\
**Post date:** [January 3, 2024, 7:32pm UTC](https://es.discourse.group/t/this-should-not-be-happening/1881/4 "2024-01-03T19:32:53Z")

</div>

That's a good point! I only just recently learned about `structuredClone` myself so I didn't think of it, but yeah - if you need or want to use the array-of-arrays style for multidimensional arrays, or if you have object members of the array that you also want cloned, `structuredClone` is a really good option for making a copy. Just be aware that any object members _will_ also be cloned, so:

```js
const apple = {type: "fruit", name: "apple"};
const carrot = {type: "vegetable", name, "carrot"};
const arrayWithObjects = [
  [apple, carrot],
  [carrot, apple],
];
const clonedArray = structuredClone(arrayWithObjects);
console.log(arrayWithObjects[0][0]); // {type: "fruit", name: "apple"}
console.log(clonedArray[0][0]); // {type: "fruit", name: "apple"}
console.log(arrayWithObjects[0][0] === apple); // true
console.log(clonedArray[0][0] === apple); // false

```
