Design & Download
Your JS Library
in Seconds!!!

Snippet: rearg() - Rewriting Arguments

Written by Christopher West (cwest) on November 08, 2015.
Reorganize or even rewrite arguments before they are passed into your function.
function rearg(fn, index0_or_argGetter) {
  if (!typeOf(index0_or_argGetter, 'Function')) {
    for (var keys = slice(arguments, 1), keysLen = keys.length, i = 0, key; key = keys[i], i < keysLen; i++) {
      keys[i] = ((/^(this|-?\d+)(?=\.|$)/.test(key) ? '' : 'this.') + key).split('.');
    }

    index0_or_argGetter = function(arg, argIndex, args, key, i, l, j) {
      if (argIndex < keysLen && (key = keys[argIndex])) {
        if (j = key[0]) {
          arg = j == 'this' ? this : slice(args, j, +j+1)[0];
          for (i = 1, l = key.length; j = key[i], i++ < l;) {
            arg = arg
                ? (typeOf(arg, 'Array') && /^-?\d+$/.test(j))
                  ? arg.slice(j, +j+1)[0]
                  : arg[j]
                : arg;
          }
        }
      }
      return arg;
    };
  }

  return function() {
    for (var args = arguments, arrArgs = [], i = Math.max(args.length, keysLen||0); i--;) {
      arrArgs[i] = index0_or_argGetter.call(this, args[i], i, args);
    }
    return fn.apply(this, arrArgs);
  }
}

Recently I have been looking into expanding the horizons of YourJS a bit so that it can also offer functionality similar to what is available in other JS utility libraries. I was looking over some of the functions available in lodash. One of the functions that caught my eye was rearg() which is used for reordering the arguments before calling the original function. This can come in handy when combining with YourJS.partial() and perhaps something like YourJS.set() or YourJS.get() to make generic getters and setters.

Parameters

  1. fn {Function}:
    The function that will be called after reordering the arguments.
  2. index0_or_argGetter {...number|...string|Function}:
    This can either be many parameters (numbers or strings) or just one as shown by the three possibilities below:
    • ...indices {number}:
      If one or more numbers are specified each number should correspond to the index of the argument that should be in that corresponding place. For example: YourJS.rearg(fn, 2, 1, 0) would change fn('a', 'b', 'c') to fn('c', 'b', 'a')
    • ...indices {string}:
      If one or more strings are specified each string should correspond to a path of the argument that should be in the corresponding place. If a path starts off with a non-digit and is not "this", it will refer to a path in the context object (this). For example: YourJS.rearg(fn, 'firstName', 'lastName', 'age', 'this') would change fn.call(ctx) to fn.call(ctx, ctx.firstName, ctx.lastName, ctx.age, ctx)
    • argGetter {function(value, index, args)}:
      If a function is specified it will be used to come up with the modified values of the arguments. It will be passed the index, value and the original arguments. It should return the value to be used in that argument position.

Returns

A new function is returned that will reorder the arguments before calling the original fn function.