Click here to Skip to main content
15,899,679 members
Articles / All Topics
Technical Blog

Variadic Functions In JavaScript

Rate me:
Please Sign up or sign in to vote.
3.33/5 (2 votes)
2 Oct 2015CPOL2 min read 17.3K   1  
A variadic function is a function where the total number of parameters are unknown and can be adjusted at the time the method is called.The C programming language, along with many others, have an interesting little feature called an ellipsis argument.

This article may contain live JavaScript that has been reviewed and tested for security. If you wish to submit articles containing JavaScript please email your submissions to submit@codeproject.com.

A variadic function is a function where the total number of parameters are unknown and can be adjusted at the time the method is called.

The C programming language, along with many others, have an interesting little feature called an ellipsis argument. When an ellipsis is used in a methods signature, that method can then accept a varying number of arguments.

Example C Variadic Function:

<code>int main(void) {
    variadic_func(4, 1, 2, 3, 4); // Returns 10 as the sum
    variadic_func(2, 1, 2); // Returns 3 as the sum
    return 0;
}

void variadic_func(int num_args, ...) {
  int ellipses_args, i;
  int sum = 0;
  va_list list_pointer;
  va_start(list_pointer, num_args);

  for(i = 0; i < num_args; i++ ) {
      ellipses_args = va_arg(list_pointer, int);
      sum = ellipses_args;
  }

  va_end(list_pointer);
  printf("%i\n", sum); // Outputs the sum of the given args
}
</code>

The variadic_func() has a signature with 2 parameters but thanks to the ellipsis it can accept a variable number of arguments. Now let's see how we can take this same concept and implement it in JavaScript.

JavaScript And ...

Since JavaScript is a functional language, every function can be variadic and in various JavaScript libraries you'll commonly see Array.prototype.slice.call(arguments) used to get a variable number of trailing arguments back as an array.

Unfortunately, JavaScript does not currently support ellipses; it is however in the works with ECMAScript 6. But for now, we are stuck implementing a function that will collect trailing arguments into an array for us:

JavaScript Variadic Implementation:

<code>(function () {
    var slice = Array.prototype.slice,
        variadic = function (fn) {
            var fnLength = fn.length;

            if (fnLength < 1 ) {
                return fn;
            }
            else if (fnLength === 1) {
                return function () {
                    return fn.call(this, slice.call(arguments, 0));
                }
            }
            else {
              return function () {
                  var numberOfArgs = arguments.length,
                      namedArgs = slice.call(arguments, 0, fnLength - 1),
                      numberOfMissingNamedArgs = Math.max(fnLength - numberOfArgs - 1, 0),
                      argPadding = new Array(numberOfMissingNamedArgs),
                      variadicArgs = slice.call(arguments, fn.length - 1);

                  return fn.apply(this, namedArgs.concat(argPadding).concat([variadicArgs]));
              }
          }
      },
      ellipsisFun = function (firstArg, ellipsis) {
          return [firstArg, ellipsis];
      };

      console.log(ellipsisFun('one', 'two', 'three')); // Returns ["one", "two"]
      console.log(variadic(ellipsisFun)('one', 'two', 'three')); // Returns ["one", ["two", "three"]]
}());
</code>

The JavaScript implementation of a variadic function takes a single function as it's argument and returns a new function that then passes in every additional argument as an array to the last parameter.

Disclaimer

In JavaScript, a functions parameters can be accessed from the arguments object.

Using Arguments Object:

<code>function argumentsObject () {
    for (var i = 0; i < arguments.length; i++) {
        console.log(arguments[i]);
    }
}

argumentsObject('I', 'should', 'sleep', 'more'); // Outputs all 4 strings to the console
</code>

One might think that going through all this trouble to create a variadic function isn't worth it. Just know that using the arguments object is considerably slower than directly accessing argument bindings.

But if performance is a top priority then you probably shouldn't be using a function that takes a variable number of arguments in that section anyway.

Practical Usage

So when would we use a variadic function?
One example, that's used often on the web, is an event triggering mechanism which accepts a variable number of arguments.

Original Trigger:

<code>function (item) {
  var args;
  if (!this._events) return this;
  args = slice.call(arguments, 1);
  return this;
}
</code>

Could be rewritten to be:

<code>variadic(function (item, args) {
  var args;
  if (!this._events) return this;
  return this;
}
</code>

Wrap up

Variadic functions are quite useful and powerful in their own way; and if used properly, in some edge cases they can improve performance. One final note; earlier in my disclaimer I stated that using the arguments object is considerably slower than not.

Here is a jsperf benchmark created by Chris Khoo that shows how slow arguments usage is. And for good measure here is a benchmark for arguments vs. array arguments. As always, if you have any questions or see any blatant mistakes in this post don't hesitate in letting me know!

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior)
United States United States
If you liked my post visit my website at http://ericanderson.io

I'm a software engineer, gamer and musician who loves all things .NET.
When I'm not spending time with my family I love learning new things about programming, talking about tech and teaching people how to code.

Currently I'm working with C#, ASP.NET, Angular.js and Node.js.

If you have any questions or concerns, please don't hesitate to reach our to me!

Need a developer to help turn your vision into reality?

I'm available for freelance work!
Send all inquiries to: freelance@ericanderson.io

Comments and Discussions

 
-- There are no messages in this forum --