Confusion about parameters involving arrays and methods in JS

https://editor.p5js.org/rachelish_/sketches/sDwPkCrO2

I’m trying to understand the code below:
okay, a few questions:

  1. why is (item, index) passed as parameters for the .foreach function, and how does this work?

  2. why is (circle, item) passed as parameters for check collision bottom?

  3. why doesn’t the word index in the splice() method work if I just have bricks.splice() alone without bricks.foreach having (item, index) as its parameters?

the following code below is not my own

bricks.forEach((item, index) =>  {
  	if(checkCollisionBottom(circle, item)){
//circle is a function written by the owner
      dy = -dy
    	score++
       bricks.splice(index, 1)
    }
  })


function checkCollisionBottom(ball, brick) {
	if (ball.y - 20 < brick.y && ball.x > brick.x && ball.x <= brick.x + 58) {	
return true
                 //ball and brick are functions written by the owner                                                          
  }
}


Thanks in advance if anyone reads this. If you can only answer one question, or have any tips + tricks, I will appreciate it!!!

Hey there,
Here’s my two cents:

.forEach() it accepts another function, known as a callback function, as a parameter, which it then executes on each element of the array. Then THAT function takes item and index as parameters. Here, the function has been passed in as an anonymous function using arrow function syntax, but it’s exactly the same as writing:

function myFunction (item, index)  {
    if(checkCollisionBottom(circle, item)){
    dy = -dy
    score++
    bricks.splice(index, 1)
    }
 }

bricks.forEach(myFunction(item,index))

When you use .forEach() with a callback function, you can pass the callback three parameters:

  • item - which is the array item to execute on
  • index - which is the index of the item you are executing it on
  • array - the whole array that .forEach was called on (not used here)

From MDN Docs:

arr.forEach(callback(currentValue[, index[, array]])

Here:

checkCollisionBottom(ball, brick) is a function defined in the global scope, so .forEach() can go and read it there. It takes two parameters, ball and brick.
When it is invoked in bricks.forEach() those parameters are specified as arguments so they have specific values:

  • The ball parameter is given the argument of circle (defined elsewhere in the global scope)
  • The brick parameter is given the argument of item which is the individual array item (brick) that the .forEach() method is currently executing on (as above).

I don’t 100% follow your question I’m afraid. You could .splice() the bricks array directly if you wanted to, but in this code the author only wants to remove the specific brick that was hit with the ball. To put the code into readable english:

  1. For each brick
  2. check if there was a collision between the brick and the ball
  3. If there was, add to the users score and find the location in the array of the brick that was hit
  4. remove that brick (so that it disappears)

If you don’t have the .forEach() function here checking each one and sharing its location (index), the computer won’t know which brick index to remove. Additionally, as the checkCollisionBottom() function only looks at one brick at a time, you would need another way to run it on every brick!

Hope this helps, I can see from your comments on the code that you had a lot of this sorted in your head already :muscle:

3 Likes

To add to data2704285749’s beautiful explanation:

  1. Under the hood, forEach looks like this:
Array.prototype.forEach = function (callback) {
	if (callback && typeof callback === 'function') {
		for (var i = 0; i < this.length; i++) {
			callback(this[i], i, this);
		}
	}
};

So, any array has a method forEach which accepts function as a parameter and calls it inside of forEach.
If you haven’t yet study prototypes - don’t go deep into Array.prototye. This is another big topic (but stydy prototypes in the future - you should at least understand the concept of it to know how JS works).

It basically means that whatever we put in the array’s prototype, it will be accessed by any array in the future. In our case forEach exists there by default.

this keyword in this very case refers to a particular array we call the method on.

Fist it checks that we indeed passed a function, not some other type - if (callback && typeof callback === 'function')
Then it iterates over the array and calls the function on each item.

Every time it passes it the current item’s value - this[i], current item’s index - i, and the array itself - this.
You can do whatever you want with them in your callback function you pass to forEach.

  1. If I understand the code correctly, checkCollisionBottom checks whether the object passed as first argument collides with the object passed as a second argument from the 1st object’s bottom.

To check this you should pass two objects to it in a specific order for the checks inside of checkCollisionBottom to work properly. The order affects the result of the comparison as you can see form the function’s body.

Both argument objects should have at least x and y fields, which, I assume, refer to their origin points coordinates. They have origins in the upper left corner and 1st object has a height of 20, 2nd object has a width of 58, and this is hardcoded in checkCollisionBottom checking expression, if I understand it correctly.

  1. item and index are totally arbitrary argument names. Order and value type of both of them is what important here. These names and their values will be accessible within you callback function only.

So having in mind what I told in 1., index - as it is called here - contains current item’s index and is passed to slice method as a first argument.

It will work too if you rewrite the code so that you have a for loop. I assume that this code’s logic requires each item’s index and if you don’t know the array’s length (which you shouldn’t) - you have to iterate over array any way you want and get each item’s index, passing it to splice method.

2 Likes

you are amazing. just absolutely fantastic. thank you so much!!!

2 Likes

thank u so much open sky!!! you are also fantastic!

2 Likes

Okay, now that i actually have the chance to sit down and code this, can you explain more about passing circle and item as an argument for check collision bottom’s brick and ball ?

Specifically, I just want to know if you can always call a function and give it parameters (given that those parameters are functions), and call it again and pass another set of parameters as arguments for those functions.

Sorry if this was confusing! I am a native English speaker but I still don’t know the language.

1 Like

Sure you can call a function and pass it parameters any number of times where you need it (unless this is an endless loop, which will lead to stability issues or even crash of your software).

See, circle and item are, let’s say, external names of the 1st and 2nd parameter of the function when you pass them to it and were defined outside of checkCollisionBottom. Inside a function these parameters are interpreted as ball and brick respectively because the function’s author called them so when the function was created. This is why the order matters. Anything passed to the function as the first argument will be handled inside of the function as a ball, as the second argument - as a brick.

Also, passing parameters to a function, be sure to check that function is able to handle them. From the checkCollisionBottom's body it is clear that it is presupposed that both parameters are objects and they have x and y fields. Otherwise you’ll get an error.

To avoid this error you can add a check if both of them are objects like this:

function checkCollisionBottom(ball, brick) {
        if (typeof ball === 'object' && ball !== null) && (typeof brick === 'object' && brick !== null) {
                if (ball.y - 20 < brick.y && ball.x > brick.x && ball.x <= brick.x + 58) {	
                        return true
                        //ball and brick are functions written by the owner                                                          
                 }
        }
}

Check if the object is not null is required since JS at times is not intuitive and it is historically so that null is an object in JS :roll_eyes:

2 Likes

Thank you so much!!! I really needed this man you’re the best!

So basically what I learned was that, since functions are things that hold stuff in them, there can be functions inside of functions like a russian nesting doll. And this russian nesting doll of functions can be achieved through using functions as parameters to other functions, and even having parameters (if theyre a function) have other parameters that are functions as long as its contents are similar (like both ball and circle having x and y). And this is why the order for parameters matter, because you can’t pass anything as a parameters if its contents arent similar.

1 Like

Russian doll resonates with me a lot :grinning:
Yeah, basically you got it. I need to mention a couple of things to make things clearer.

Functions are mostly for processing, not storing. They are in a nutshell a repetitive section of code you don’t want to copy/paste. You just put this code in a function, define several arguments if you want to pass it anything, and return a result if you need it. After that you just call a function wherever you’d copy/paste the code it contains.

Nested functions are pieces of code you don’t want to repeat inside of pieces of code you don’t want to repeat. Also nested functions allow for customization of this piece of code. You could make a function which iterates over an array and does something on each item - but what exactly - you want to leave to the function’s user (yourself in the future or your teammates). This is achieved with this callback function concept - you just leave this to the future function’s user by making one of the arguments a function. This is exactly how forEach works.

However, in JS (but not exclusively in JS) there are such concepts as closure and carrying which allows for holding an info for a while using functions (you’ll learn them in the future).

Function is one of the core concepts of software engineering and you’re doing a great job of understanding it.

1 Like

@opensky1988 @data2704285749
Welp I tried, but thanks for helping me! I got somewhere with my project, and that’s thanks to you guys. Still building on the game, because this is a REALLY rough draft.

https://editor.p5js.org/rachelish_/sketches/qD9GoxUhP