Making basic physics object class
Poor performance

For games performance dominates all levels of design but becomes critical as you approach the low level building blocks of the game. Every increase in performance opens up your market, there are far more low end devices than high end with a 20% performance increase doubling the number of devices that can run the game at acceptable levels.

If you are not interested in marketing and its just for fun, then you can solve performance problems with hardware and ignore this answer.

Some points on performance


Avoid getters and setters as they are slower than direct property access.
Avoid array iteration for small arrays. Inline the operations.
Be memory efficient, pre-allocate, reuse rather than deference (delete)
Use small generic objects to cover a wide range of uses, rather than many complex targeted objects


Array.slice and Array.map require allocation and GC overhead. 
Array iterators require closure, counters, and logic overheads. For large arrays the overheads become insignificant, but for small arrays 2,3 items long the overhead becomes a significant part of the processing.

One of the biggest overheads of using array iteration is that the coder hides a large number of redundant operations because the iterators obscure the expanded calculations.

Needless CPU wastage

Lets analyze and simplify the function simulatePhysics as it is very inefficient with a lot of repeated calculations, or completely unneeded calculations. Every time it is called it create a lot of garbage for GC to clean up (15 new Array objects)


  simulatePhysics(dt) {
    function taylor(arr) {
      return arr.reduceRight((acc, cur, i) =&gt; acc * dt / (i + 1) + cur, 0)
    }

    for (var dim = 0; dim &lt; this.motion[0].length; dim++) {
      for (var deriv = 0; deriv &lt; this.motion.length; deriv++) {
        this.motion[deriv][dim] = taylor(this.motion.slice(deriv).map((cur) =&gt; cur[dim]))
      }
    }

    for (var deriv = 0; deriv &lt; this.angMotion.length; deriv++) {
      this.angMotion[deriv] = taylor(this.angMotion.slice(deriv))
    }
  }



This function requires the creation of 15 new arrays, 27 call stack push and pops, 30 temp variable, and 108 math operations. 

It can be significantly reduced to no new arrays, no call stack overhead, 6 temp variable, and 19 math operations.

Reducing simulatePhysics

The steps I used to simplify the function and remove unneeded overhead.

1 First to remove all the coding noise we can create some aliases for the names.

 const m = this.motion;
 const aM = this.angMotion;


2 Inline the 2 loops removing all the iterators slice and map overhead.

 m[0][0] = taylor([m[0][0], m[1][0], m[2][0]])
 m[1][0] = taylor([m[1][0], m[2][0]])
 m[2][0] = taylor([m[2][0]])
 m[0][1] = taylor([m[0][1], m[1][1], m[2][1]])
 m[1][1] = taylor([m[1][1], m[2][1]])
 m[2][1] = taylor([m[2][1]])   


 aM[0] = taylor([aM[0], aM[1], aM[2]])  
 aM[1] = taylor([aM[1], aM[2]])  
 aM[2] = taylor([aM[2]])  


3 Replace the taylor function with inlined calculations 

  m[0][0] = ((0 * dt / 3 + m[2][0]) * dt / 2 + m[1][0]) * dt / 1 + m[0][0]
  m[1][0] = (0 * dt / 2 + m[2][0]) * dt / 1 + m[1][0]
  m[2][0] = 0 * dt / 1 + m[2][0]
  m[0][1] = ((0 * dt / 3 + m[2][1]) * dt / 2 + m[1][1]) * dt / 1 + m[0][1]
  m[1][1] = (0 * dt / 2 + m[2][1]) * dt / 1 + m[1][1]
  m[2][1] = 0 * dt / 1 + m[2][1]


  aM[0] = ((0 * dt / 3 + aM[2]) * dt / 2 + aM[1]) * dt / 1 + aM[0]
  aM[1] = (0 * dt / 2 + aM[2]) * dt / 1 + aM[1]
  aM[2] = 0 * dt / 1 + aM[2]


4 Remove the multiply by zero and divide by ones

  m[0][0] = (m[2][0] * dt / 2 + m[1][0]) * dt + m[0][0]
  m[1][0] = m[2][0] * dt + m[1][0]
  m[2][0] = m[2][0]
  m[0][1] = (m[2][1] * dt / 2 + m[1][1]) * dt + m[0][1]
  m[1][1] = m[2][1] * dt + m[1][1]
  m[2][1] = m[2][1]


  aM[0] = (aM[2] * dt / 2 + aM[1]) * dt + aM[0]
  aM[1] = aM[2] * dt + aM[1]
  aM[2] = aM[2]


5 Cache and substitute with constants, remove unneeded assignments.

 const dt2 = dt / 2;

 m[0][0] = (m[2][0] * dt2 + m[1][0]) * dt + m[0][0]
 m[1][0] = m[2][0] * dt + m[1][0]
 m[0][1] = (m[2][1] * dt2 + m[1][1]) * dt + m[0][1]
 m[1][1] = m[2][1] * dt + m[1][1]

 aM[0] = (aM[2] * dt2 + aM[1]) * dt + aM[0]
 aM[1] = aM[2] * dt + aM[1]


6 More aliases to reduce indexing overhead and rebuild the function

simulatePhysics(dt) {
    const m = this.motion, m0 = m[0], m1 = m[1], m2 = m[2];
    const aM = this.angMotion;
    const dt2 = dt / 2;

    m0[0] = (m2[0] * dt2 + m1[0]) * dt + m0[0];
    m1[0] =  m2[0] * dt  + m1[0];
    m0[1] = (m2[1] * dt2 + m1[1]) * dt + m0[1];
    m1[1] =  m2[1] * dt  + m1[1];
    aM[0] = (aM[2] * dt2 + aM[1]) * dt + aM[0];
    aM[1] =  aM[2] * dt  + aM[1];

}


Whats the gain

Arguably there is some loss in readability, personally it makes a lot more sense than a collection of arrays iterators and copying. But the gain is (tested on chrome) huge.

// tested on random set of 1000 objects
// µs is 1/1,000,000th second. OPS is operations per second. 
// An operation is a single call to the function being tested.
Optimized..: MeanTime 0.175µs OPS 5,710,020 Test Total   322ms 1,836,000 operations
Original...: MeanTime 4.198µs OPS   238,185 Test Total 6,566ms 1,564,000 operations


The optimized version is 25 times faster, able to do 5.7million operations in the same time as the original could do 0.3million

Is readability more important than performance? for games you must seriously consider what you lose via traditional coding styles.