Javascript run length encoding algorithm
Separation of concerns

The problem has two distinct, independent components:


Compute run length
Decide if two values are equal


I agree that using reduce makes sense here to compute the run length.
If you separate this computation from the equality decision,
the logic of the reducer can become a lot simpler:

  const reducer = (acc, val) =&gt; {
    if (acc.length &gt; 0 &amp;&amp; equals(acc[acc.length - 1][1], val)) {
      acc[acc.length - 1][0]++;
      return acc;
    }
    acc.push([1, val]);
    return acc;
  };
  return arr.reduce(reducer, []);


That is:


When the accumulator is not empty, and the last element has matching value,
then increment the count of the last element, and return the accumulator.
Append [1, val] to the accumulator.
The accumulator starts empty.


The equality condition is to be implemented.
You can even require the implementation to be passed in as parameter.

As @radarbob suggests,
it's good to get the run-length computation working without worrying about mixed value types.
The implementation of the equals function here is not interesting at all for run-length computation.
You can start with a simple const equals = (a, b) =&gt; a === b.
Having mixed values in the input doesn't affect at all the run-length computation logic.

The converse is also true: it should be possible to implement the equality logic independently from run-length.
This reduces your mental burden and helps you think clearly,
focusing on one problem at a time.
I came up with this:

  const equals = (a, b) =&gt; {
    if (a === b) {
      return true;
    }
    if (typeof(a) !== typeof(b)) {
      return false;
    }
    if (Array.isArray(a)) {
      return arrayEquals([a, b]);
    }
    return false;
  };


This implementation handles some easy basic cases,
and delegates some non-trivial ones,
such as comparing arrays.
Your arrayEquals will work nicely for the purpose.
Looking at this implementation,
it's also quite clear what kind of values are supported:
primitive and arrays only.
(As far as we can trust the externalized arrayEquals implementation...)