kgzygw
Last Updated: February 25, 2016
·
1.201K
· jeroen_ransijn

Exotic JavaScript add function — Advanced JS

A JavaScript quiz (including answers) on github showed this question:

"(question 16) Write a function named add that returns the total of any number of parameters. Example…"

// Should equal 15
add(1, 2, 3, 4, 5);

// Should equal 0
add(5, null, -5);

// Should equal 10
add('1.0', false, 1, true, 1, 'A', 1, 'B', 1, 'C', 1, 'D', 1, 'E', 1, 'F', 1, 'G', 1);

// Should equal 0.3, not 0.30000000000000004
add(0.1, 0.2);

Note: view the gist of this post here if you prefer

And the answer they give works, nothing exotic about this:

function add() {

  // Start from zero
  var total = 0;

  // Floating-points, bah!
  // 1e12 = 1000000000000.
  var factor = 1e12;

  // Undefined, set in the loop
  var value;

  // Something to iterate on
  var i = arguments.length;

  // Loop through all the parameters
  while (i--) {
    // Multiply by 1e12, to account for peculiarities
    // of doing addition with floating-point numbers.
    value = parseFloat(arguments[i]) * factor;

    // Is it not, not a number?
    // Then hey, it's a number!
    if (!isNaN(value)) {
       total += value;
    }
  }

  // Divide back by 1e12, because we multiplied by
  // 1e12 to account for floating-point weirdness.
  return total/factor;
}

This could be more compact I thought. While I was writing this there were quite some things I never did before, and never thought about it would work. When I tested it, it worked(!) only I had to add this ugly line typeof arg[0] === 'boolean' to catch true values, making it seem somewhat less concise.

// can you figure it out?
function add() {
  var args = [].slice.call(arguments), total = 0;

  for (;args.length; args.shift()) {
    !args[0] || typeof args[0] === 'boolean' || (total += parseFloat( !(args[0]*1) ? 0 : args[0] ) * 1e12); 
  }

  return total/1e12;
}

Benchmark

For fun I decided to check out what would be faster, view the results on jsperf. My version is about 40% slower on Chrome, but I figure it's slower in general because of the array copy and the array shift calls, but it could be something else even more (let me know if you have an idea).