2 Answers
2

Try not to define methods inside the Ball constructor, it uses more memory since a new function is created for each ball instance. Rather create them using ES2016 classes (if available) or defining them on the prototype.

Rather than defining getX, getY, etc, methods rather create properties (again using ES2016 syntax if possible or otherwise defineProperty)

I would add draw and checkCollision methods to the Ball class and move the code there.

I would add a class and objects for the walls. This has the advantage that they can draw themselves in the same way as a Ball (The main program just becomes a loop asking every object to draw itself) and that you can generalize collision detection as just being between two objects without worrying about their types. As you add different objects to your code this keeps things much simpler.

Simulating the kinematics of rigid bodies over time requires integrating over their velocities to find their positions. As you don't have any additional forces such as gravity or springs acting on those bodies, this step could be as simple as object.x += object.vx * dt where dt denotes the time passed between two frames which you might want to supply via Board.frame(dt).

However, when collisions occur, the velocities have discontinuities. Therefore, you might want to update object positions as above only until a collision occurs. Then you compute the new velocities and continue with the integration. Even though your bodies are just balls and therefore pretty simple, this can easily become tedious and problematic when the time between collisions becomes very small. An alternative and more generalizable approach is to update object positions without regard for collisions and then resolve collisions in a dedicated step.

Contrary to @MarcRohloff's suggestion, I'd recommend updating the ball movements by a dedicated physics "engine" which can be part of the Board as knowledge about the complete board state is necessary in order to update a ball's position.

Graphics:

I also recommend keeping your drawing routines separate from your models. A dedicated graphics "engine" can perform optimizations such as minimizing the number of context state changes or apply global effects such as z-sorting which requires knowledge about the complete board state.

Apart from that, I recommend following the advice given by @MarcRohloff.