# RMMVHow to make an easy to understand multi-dimensional array in javascript

#### bishiba

If you are in need of making a multi-dimensional array but you are like me, and find the available suggestions if how to do it a bit, abstract(?), then go ahead and just use my little code snippet.

The only downside to it is that it needs to be set up with 2 lines. But other than that is more easy to understand, and works like any other array.

JavaScript:
``grid.p[x + "," + y] = element;``
So at first you declare z to be x and y separated with a comma. It essentially looks this way: grid.p["x,y"]. Imo it's even more straightforward than say grid.p[x][y], which is a real multi-dimensional array.

if you want to see it working you can just put the below into any javascript and run the makeNoise(density) function followed by the drawGrid() function.

JavaScript:
``````grid = {};
grid.size = 14;
grid.p = [];
tWall = "X";
tFloor = "O";

function makeNoise(density) {
for (x = 0; x < grid.size; x++) {
for (y = 0; y < grid.size; y++) {
rand = Math.random()*100;
if (density > rand) {
grid.p[x + "," + y] = tWall;
} else {
grid.p[x + "," + y] = tFloor;
}
}
rand = Math.random()*100;
if (density > rand) {
grid.p[x + "," + y] = tWall;
} else {
grid.p[x + "," + y] = tFloor;
}
}
}

function drawGrid() {
let s = "";
for (x = 0; x < grid.size; x++) {
for (y = 0; y < grid.size; y++) {
s += grid.p[x+"," + y];
}
s += grid.p[x + "," + y] + "\n";
}
console.log("grid:\n" + s);
}``````

I am no code master, but this felt really useful and I hope someone will find it helpful as well.

Should produce something like this in the console:

Last edited:

#### Nolonar

##### Veteran
A few suggestions (remember: these are just suggestions; feel free to completely disregard them, especially if you feel confused):

Avoid declaring variables without `var`, `let`, or `const`. For example:
JavaScript:
``````const grid = {};
const tWall = "X";
const tFloor = "O";``````

Without these keywords, you are creating a global variable. Global variables are convenient, but they can also cause all sorts of bugs that are extremely difficult to fix, if you don't use them properly. You should never use global variables without a good reason.

The `const` keyword also serves as a kind of sanity check, as it throws an error if you try to change its value (because `const` denotes a constant, which should never change). Remember: errors help you find bugs! Avoiding or ignoring errors does not get rid of bugs; it only makes them much harder to find and fix.

Also, `const` prevents you from changing the value of the object, but it doesn't stop you from changing the value of its properties. So `grid.p = []` is still possible, even if `grid` is a `const`.

JavaScript:
``````grid = {};
grid.size = 14;
grid.p = [];``````

You can do:
JavaScript:
``````const grid = {
size: 14,
p: []
};``````

This makes it more obvious that `grid` is supposed to have `size` and `p`. If you use an IDE (which I'd recommend, as it makes coding that much easier), this'll help your IDE tell you what properties your `grid` object has, and what type you should expect from these properties (like `size: Number` and `p: Array`).

Also, don't be afraid of using default values when you don't know the actual value yet. For example, if you don't know yet that `size: 14`, don't be afraid to initialize it with `size: 0` and later set it with `grid.size = 14`, so your IDE at least knows that `grid.size` is a `Number`.

Instead of `for (x = 0; /* bla */)`, use `for (var x = 0; /* bla */)`, or if you can, `for (let x = 0; /* bla */)`.

I've already explained why global variables can be dangerous, so I'll use this opportunity to explain why you should always use `let` over `var`, if possible.

Originally, there was no `let` keyword. This means that your code may run on an old browser that doesn't know what to do with it (such as the nw.js engine that ships with RPG Maker MV before 1.5.0). If that's the case, you have no other choice but to use `var` instead.

The key difference between the two keywords is the scope, which defines where in your code you can use the variable. `var` has a function scope, while `let` has the much more intuitive block scope. Example (shamelessly ripped off from https://stackoverflow.com/a/11444416/1169228):
JavaScript:
``````var funcs = [];

// let's create 3 functions
for (var i = 0; i < 3; i++) {
// and store them in funcs
funcs[i] = function() {
// each should log its value.
console.log("My value: " + i);
};
}

for (var j = 0; j < 3; j++) {
// and now let's run each one to see
funcs[j]();
}``````

You expect to see values 1, 2, and 3, but instead all three values are 3. That's because `var i` is valid throughout the function in which the `for()` loop is. Thus, its value is 3 for each function, by the time you execute the three functions. With `let i`, the variable would instead be valid only within the `for()` loop, and its value would therefore be different for each function.

In fact, using `let y` would've caused an error, with which you'd have noticed my next piece of advice:

Your `makeNoise()` function is creating a grid that's larger than expected (notice how your grid has 15 rows and columns, even though you defined `grid.size = 14`). This is the correct code:
JavaScript:
``````function makeNoise(density) {
for (let x = 0; x < grid.size; x++) {
for (let y = 0; y < grid.size; y++) {
const rand = Math.random()*100;
if (density > rand) {
grid.p[x + "," + y] = tWall;
} else {
grid.p[x + "," + y] = tFloor;
}
}
}
}``````

The same applies to your `drawGrid()` function:
JavaScript:
``````function drawGrid() {
let s = "";
for (let x = 0; x < grid.size; x++) {
for (let y = 0; y < grid.size; y++) {
s += grid.p[x+"," + y];
}
s += "\n";
}
console.log("grid:\n" + s);
}``````

Instead of letting your `makeNoise()` function write in your `grid` object, you might want to have a `createGrid()` function instead, which creates an independent array and returns it, then set `grid.p = createGrid()` (or `p: createGrid()` if you want to initialize it directly). This reduces coupling in your code (see: https://en.wikipedia.org/wiki/Coupling_(computer_programming)). Passing the `grid.size` as argument to the `createGrid()` function also reduces coupling.

The reason for reducing coupling, is that you can now use `createGrid()` without affecting your `grid` object. In this specific case it's not really that important, but as your project grows larger and larger, you'll eventually want to reuse existing functions, or rename certain objects or properties. High coupling hurts maintainability. It's always a good idea to keep this in mind and strive for low coupling, even in small projects.

Here's an example:
JavaScript:
``````function createGrid(size, density) {
const data = [];
for (let x = 0; x < size; x++) {
for (let y = 0; y < size; y++) {
data[x + "," + y] = density > Math.random() * 100 ? tWall : tFloor;
}
}
return data;
}

grid.p = createGrid(grid.size, 50);``````

Notice how I'm creating and returning an independent `data` array, and how I'm replacing `grid.p` with the `data` array from `createGrid()`. Also note how my `createGrid()` function can retrieve the `size` regardless of the `grid` object. This allows me to easily do stuff like this:
JavaScript:
``````const grid1 = {
size: 10,
p: createGrid(10, 50)
};

const grid2 = {
size: 14,
p: createGrid(14, 50)
};``````
if I need multiple grids of different size.

Of course, you can further reduce coupling by having the `drawGrid()` function expect a `grid` argument, instead of using the global `grid` object. This would allow you to draw any grid, not just the global `grid` object.

Now that I've given you all this advice, I'd like to comment on your trick to more easily understand multi-dimensional arrays.

First of all, what you have here is not a multi-dimensional array; it's a dictionary. Without going too much into detail regarding the differences between an array and a dictionary, a dictionary requires more memory and is slower. Modern computers have plenty of memory and are plenty fast, so unless you have a huge grid or need to access it all the time (e.g. it's the grid for your game), this isn't really much of a problem.

Technically, JavaScript doesn't have "multi-dimensional arrays", so the closest you'll get are "jagged arrays" (arrays within arrays). While it may seem confusing to access a grid with `grid[y][x]` instead of `grid[x][y]`, it's really just a matter of getting used to it.

There are also a few advantages (beyond performance) to properly using jagged arrays:
JavaScript:
``````const map = [
["+", "-", "-", "+"],
["|", "O", "O", "|"],
["|", "O", "O", "|"],
["+", "-", "-", "+"]
];``````
This is pretty convenient when you want to create predefined maps (as opposed to procedurally generating them). This would be much more difficult to do with a dictionary:
JavaScript:
``````const map = {
"0,0": "+", "0,1": "|", "0,2": "|", "0,3": "+",
"1,0": "-", // etc.
};``````

Your drawGrid() function could also be shorter if you used jagged arrays (the next code assumes that `grid` is a jagged array, rather than an object with properties `size` and `p`):
JavaScript:
``````function drawGrid(grid) {
let s = "";
for (const y in grid) {
for (const c of grid[y]) {
s += c;
}
s += "\n";
}
console.log("grid:\n" + s);
}``````

And even shorter if you use the `Array.join()` function:
JavaScript:
``````function drawGrid(grid) {
let s = "";
for (const y in grid) {
s += grid[y].join("") + "\n";
}
console.log("grid:\n" + s);
}``````

And even shorter with `Array.map()`:
JavaScript:
``````function drawGrid(grid) {
const s = grid.map(row => row.join("")).join("\n");
console.log("grid:\n" + s);
}``````

Doing the same with a dictionary would be quite a bit harder.

If you need help understanding jagged arrays, consider my `map` object earlier:
JavaScript:
``````const map = [
["+", "-", "-", "+"],
["|", "O", "O", "|"],
["|", "O", "O", "|"],
["+", "-", "-", "+"]
];``````

As you can see, it's an "array of rows" (where each row is itself an array).
Therefore, if you want to access a specific field, you must first access the row itself. Hence why you need `map[y][x]` to access each field, since each row is on a different y-coordinate.

Last edited:

#### bishiba

A few suggestions (remember: these are just suggestions; feel free to completely disregard them, especially if you feel confused):

Avoid declaring variables without `var`, `let`, or `const`. For example:
JavaScript:
``````const grid = {};
const tWall = "X";
const tFloor = "O";``````

Without these keywords, you are creating a global variable. Global variables are convenient, but they can also cause all sorts of bugs that are extremely difficult to fix, if you don't use them properly. You should never use global variables without a good reason.

The `const` keyword also serves as a kind of sanity check, as it throws an error if you try to change its value (because `const` denotes a constant, which should never change). Remember: errors help you find bugs! Avoiding or ignoring errors does not get rid of bugs; it only makes them much harder to find and fix.

Also, `const` prevents you from changing the value of the object, but it doesn't stop you from changing the value of its properties. So `grid.p = []` is still possible, even if `grid` is a `const`.

JavaScript:
``````grid = {};
grid.size = 14;
grid.p = [];``````

You can do:
JavaScript:
``````const grid = {
size: 14,
p: []
};``````

This makes it more obvious that `grid` is supposed to have `size` and `p`. If you use an IDE (which I'd recommend, as it makes coding that much easier), this'll help your IDE tell you what properties your `grid` object has, and what type you should expect from these properties (like `size: Number` and `p: Array`).

Also, don't be afraid of using default values when you don't know the actual value yet. For example, if you don't know yet that `size: 14`, don't be afraid to initialize it with `size: 0` and later set it with `grid.size = 14`, so your IDE at least knows that `grid.size` is a `Number`.

Instead of `for (x = 0; /* bla */)`, use `for (var x = 0; /* bla */)`, or if you can, `for (let x = 0; /* bla */)`.

I've already explained why global variables can be dangerous, so I'll use this opportunity to explain why you should always use `let` over `var`, if possible.

Originally, there was no `let` keyword. This means that your code may run on an old browser that doesn't know what to do with it (such as the nw.js engine that ships with RPG Maker MV before 1.5.0). If that's the case, you have no other choice but to use `var` instead.

The key difference between the two keywords is the scope, which defines where in your code you can use the variable. `var` has a function scope, while `let` has the much more intuitive block scope. Example (shamelessly ripped off from https://stackoverflow.com/a/11444416/1169228):
JavaScript:
``````var funcs = [];

// let's create 3 functions
for (var i = 0; i < 3; i++) {
// and store them in funcs
funcs[i] = function() {
// each should log its value.
console.log("My value: " + i);
};
}

for (var j = 0; j < 3; j++) {
// and now let's run each one to see
funcs[j]();
}``````

You expect to see values 1, 2, and 3, but instead all three values are 3. That's because `var i` is valid throughout the function in which the `for()` loop is. Thus, its value is 3 for each function, by the time you execute the three functions. With `let i`, the variable would instead be valid only within the `for()` loop, and its value would therefore be different for each function.

In fact, using `let y` would've caused an error, with which you'd have noticed my next piece of advice:

Your `makeNoise()` function is creating a grid that's larger than expected (notice how your grid has 15 rows and columns, even though you defined `grid.size = 14`). This is the correct code:
JavaScript:
``````function makeNoise(density) {
for (let x = 0; x < grid.size; x++) {
for (let y = 0; y < grid.size; y++) {
const rand = Math.random()*100;
if (density > rand) {
grid.p[x + "," + y] = tWall;
} else {
grid.p[x + "," + y] = tFloor;
}
}
}
}``````

The same applies to your `drawGrid()` function:
JavaScript:
``````function drawGrid() {
let s = "";
for (let x = 0; x < grid.size; x++) {
for (let y = 0; y < grid.size; y++) {
s += grid.p[x+"," + y];
}
s += "\n";
}
console.log("grid:\n" + s);
}``````

Instead of letting your `makeNoise()` function write in your `grid` object, you might want to have a `createGrid()` function instead, which creates an independent array and returns it, then set `grid.p = createGrid()` (or `p: createGrid()` if you want to initialize it directly). This reduces coupling in your code (see: https://en.wikipedia.org/wiki/Coupling_(computer_programming)). Passing the `grid.size` as argument to the `createGrid()` function also reduces coupling.

The reason for reducing coupling, is that you can now use `createGrid()` without affecting your `grid` object. In this specific case it's not really that important, but as your project grows larger and larger, you'll eventually want to reuse existing functions, or rename certain objects or properties. High coupling hurts maintainability. It's always a good idea to keep this in mind and strive for low coupling, even in small projects.

Here's an example:
JavaScript:
``````function createGrid(size, density) {
const data = [];
for (let x = 0; x < size; x++) {
for (let y = 0; y < size; y++) {
data[x + "," + y] = density > Math.random() * 100 ? tWall : tFloor;
}
}
return data;
}

grid.p = createGrid(grid.size, 50);``````

Notice how I'm creating and returning an independent `data` array, and how I'm replacing `grid.p` with the `data` array from `createGrid()`. Also note how my `createGrid()` function can retrieve the `size` regardless of the `grid` object. This allows me to easily do stuff like this:
JavaScript:
``````const grid1 = {
size: 10,
p: createGrid(10, 50)
};

const grid2 = {
size: 14,
p: createGrid(14, 50)
};``````
if I need multiple grids of different size.

Of course, you can further reduce coupling by having the `drawGrid()` function expect a `grid` argument, instead of using the global `grid` object. This would allow you to draw any grid, not just the global `grid` object.

Now that I've given you all this advice, I'd like to comment on your trick to more easily understand multi-dimensional arrays.

First of all, what you have here is not a multi-dimensional array; it's a dictionary. Without going too much into detail regarding the differences between an array and a dictionary, a dictionary requires more memory and is slower. Modern computers have plenty of memory and are plenty fast, so unless you have a huge grid or need to access it all the time (e.g. it's the grid for your game), this isn't really much of a problem.

Technically, JavaScript doesn't have "multi-dimensional arrays", so the closest you'll get are "jagged arrays" (arrays within arrays). While it may seem confusing to access a grid with `grid[y][x]` instead of `grid[x][y]`, it's really just a matter of getting used to it.

There are also a few advantages (beyond performance) to properly using jagged arrays:
JavaScript:
``````const map = [
["+", "-", "-", "+"],
["|", "O", "O", "|"],
["|", "O", "O", "|"],
["+", "-", "-", "+"]
];``````
This is pretty convenient when you want to create predefined maps (as opposed to procedurally generating them). This would be much more difficult to do with a dictionary:
JavaScript:
``````const map = {
"0,0": "+", "0,1": "|", "0,2": "|", "0,3": "+",
"1,0": "-", // etc.
};``````

Your drawGrid() function could also be shorter if you used jagged arrays (the next code assumes that `grid` is a jagged array, rather than an object with properties `size` and `p`):
JavaScript:
``````function drawGrid(grid) {
let s = "";
for (const y in grid) {
for (const c of grid[y]) {
s += c;
}
s += "\n";
}
console.log("grid:\n" + s);
}``````

And even shorter if you use the `Array.join()` function:
JavaScript:
``````function drawGrid(grid) {
let s = "";
for (const y in grid) {
s += grid[y].join("") + "\n";
}
console.log("grid:\n" + s);
}``````

And even shorter with `Array.map()`:
JavaScript:
``````function drawGrid(grid) {
const s = grid.map(row => row.join("")).join("\n");
console.log("grid:\n" + s);
}``````

Doing the same with a dictionary would be quite a bit harder.

If you need help understanding jagged arrays, consider my `map` object earlier:
JavaScript:
``````const map = [
["+", "-", "-", "+"],
["|", "O", "O", "|"],
["|", "O", "O", "|"],
["+", "-", "-", "+"]
];``````

As you can see, it's an "array of rows" (where each row is itself an array).
Therefore, if you want to access a specific field, you must first access the row itself. Hence why you need `map[y][x]` to access each field, since each row is on a different y-coordinate.
Oh wow, thanks a lot for so much of this. My pride forced me to inform you that I knew some of this, like say how to declare variables, also that let and I think also const are more recent. A big reason for the lackluster function is that it is written in my phone lol...

But so much of what you wrote is both clear and amazing that you'd spend so much time on it. I just wanted to give a tiny advice for multidim arrays and I get a nice lesson Pretty happy I included the functions at this point

I haven't yet read everything, on my way out, but this is something I will go over in detail. Even the variables part I can learn more from, but... Doesn't the for function automatically set the declared variable as function specific? It does in java, which is where I am having some formal education. But there are quite a few differences...
I had issues with specifically creating global variables so I did start doing it, but I think I forgot it since again, it's written on the phone

And thanks for showing the problem with the makeNoise() function. I would've gotten it eventually, I mean I have learnt what I know primarily by backtracking the code available. But I'm not scared to ask for help, and I really appreciate that you showed the error in the code. Now it is quite obvious. For some reason I imagined that the loop would do the x row and then add the y value. Thinking about it, it obviously just adds one more value to the same row

Could you perhaps look into my other post as well? I've solved it another way but I want to know if it is possible the way I thought it worked?

#### Nolonar

##### Veteran
Doesn't the for function automatically set the declared variable as function specific? It does in java, which is where I am having some formal education. But there are quite a few differences...
Unfortunately not. At least not without putting `var` in front of the variable name.

You can easily check this yourself: In JavaScript all global variables are stored in the `window` object. So when you create a global variable, for example with `testvar = 42`, you'll see that `window.testVar` is also 42. And when you do `for (x = 0; x < 100; x++) {}` then `window.x` will also be 100 once the `for` loop has ended.

Could you perhaps look into my other post as well? I've solved it another way but I want to know if it is possible the way I thought it worked?
I had a look at it, though I'm not entirely sure I understand how you intended to use the code, so I'm not sure if my answer is helpful to you.

### Latest Profile Posts

wow, Surface Tension is really one MF of an FPS level huh
So, I got let go from my current job because my skill set didn't align with the department's goals anymore. I have some hope, because I am currently in contact with a manager from a different department, and they are desperate for more employees. We'll see what happens...

Worked on some face-sets. Need to finish up the lot and cut some out of the game. She's looking pretty cute.
Even though I'm not going for the first time in...ten years or something...ordered my Gen Con dice!
Will be focusing on map making today and adding locked chests