We could dry this up a bit, considering the `reduce` blocks are basically identical.  How about the conditional just affects the `paramNames` value:

if (pattern instanceof RegExp) {
  paramNames = paramsArray.map(function(val, i) { return String(i); });
} else {
  paramNames = ...
}

params = (paramNames || []).reduce(function(memo, name, i) {...