freeCodeCamp Challenge Guide: Arguments Optional

Arguments Optional


Problem Explanation

It can be quite complicated to understand what needs to be done. There are always many ways to do something when coding but regardless of the algorithm used, we have to create a program that does the following:

  • It has to add two numbers passed as parameters and return the sum.
  • It has to check if any of the numbers are actual numbers, otherwise return undefined and stop the program right there.
  • It has to check if it has one or two arguments passed. More are ignored.
  • If it has only one argument then it has to return a function that uses that number and expects another one, to then add it.

Relevant Links


Hints

Hint 1

Every time you deal with an argument, you have to check if it is a number or not. For this a function that handles this task will save you repeated code.

Hint 2

When working on the case that it needs to return the function, it is wise to check if the first and only argument is a number again and base the code on that.

Hint 3

In the case that only one argument was passed, do not worry about how to prompt input for the second one, just make the function definition properly and things will work out the way they should.


Solutions

Solution 1 (Click to Show/Hide)
function addTogether() {
  // Function to check if a number is actually a number
  // and return undefined otherwise.
  var checkNum = function(num) {
    if (typeof num !== "number") {
      return undefined;
    } else return num;
  };

  // Check if we have two parameters, check if they are numbers
  // handle the case where one is not
  // returns the addition.
  if (arguments.length > 1) {
    var a = checkNum(arguments[0]);
    var b = checkNum(arguments[1]);
    if (a === undefined || b === undefined) {
      return undefined;
    } else {
      return a + b;
    }
  } else {
    // If only one parameter was found, returns a new function that expects two
    // Store first argument before entering the new function scope
    var c = arguments[0];

    // Check the number again, must be outside the function to about returning an object
    // instead of undefined.
    if (checkNum(c)) {
      // Return function that expect a second argument.
      return function(arg2) {
        // Check for non-numbers
        if (c === undefined || checkNum(arg2) === undefined) {
          return undefined;
        } else {
          // if numbers then add them.
          return c + arg2;
        }
      };
    }
  }
}

// test here
addTogether(2, 3);

Code Explanation

  • First, I create a function with the sole purpose of checking if a number is actually a number and returns undefined if it is not. It uses typeof to check.
  • Check if we have two parameters, if so, then check if they are numbers or not using the checkNum function I created.
  • If they are not undefined then add them and return the addition. If they any of them is undefined then return undefined.
  • In the case that we only have one argument, then we return a new function that expects two parameters. For this we store the first argument before going into a new scope to avoid our arguments being overwritten.
  • Still inside the big else, we need to check the argument we saved, if it is a number then we return the function expecting a second argument.
  • Now inside the function we are returning, we have to check for non numbers again just as at the beginning using checkNum if undefined then return that, otherwise if numbers add them and return the addition.

Relevant Links

Solution 2 (Click to Show/Hide)
function addTogether(first, second) {
  if (typeof first !== "number") {
    return undefined;
  }
  const sum = second =>
    typeof second === "number" ? first + second : undefined;
  return typeof second === "undefined" ? second => sum(second) : sum(second);
}
// test here
addTogether(2, 3);

Code Explanation

  • Return undefined if first argument is not a number or second argument is defined, but not a number.
  • Return sum of the arguments if both are provided otherwise return a sum function.

Relevant Links

Solution 3 (Click to Show/Hide)
//jshint esversion: 6
function addTogether() {
  var args = Array.from(arguments);
  return args.some(n => typeof n !== "number")
    ? undefined
    : args.length > 1
    ? args.reduce((acc, n) => (acc += n), 0)
    : n => (typeof n === "number" ? n + args[0] : undefined);
}

// test here
addTogether(2, 3);

Code Explanation

  • First I iterate through the arguments and check for arguments that are not a number and return undefined
  • If it’s not I then check if the arguments length is above 1, if it is I sum the arguments using Array.prototype.reduce
  • Else I return a function that checks if the passed in argument is a number and sum it, if not return undefined

Relevant Links

12 Likes

This is my solution. It is shorter but not sure if it is as robust as the “official” solutions. (I don’t see the need to use the “arguments” object.)

function addTogether(a, b) {
  // only if valid number provided
  if (Number.isFinite(a)) {
    if (!b) {
      return function(c) {
        if (Number.isFinite(c)) {
          return a + c;
        }
      };
    }
    else if (Number.isFinite(b)) {
      return a + b;
    }
  }
  // returns undefined by default
}

addTogether(2,3);



16 Likes

Cleanest “Basic Code Solution” I came up with so far (using the arguments object):

function addTogether() {
  //Variable and subroutine declaration (optional, but makes code cleaner)
  var args = arguments;
  var a = args[0];
  var b = args[1];
  function isNum(num) {
    return Number.isInteger(num);
  }

  //Actual program: relies on implicit return of 'undefined'
  //Note: while refactoring I remove curly braces if not required
  if (isNum(a)) {
    if (isNum(b))
      return a + b;
    else if (!b)
      return function(b) {
        if (isNum(b))
          return a + b;
      };
  }
}
20 Likes

In all of the examples, if you test something where you have one argument that is not a number, such as addTogether("string")(3); it always results in TypeError: addTogether(...) is not a function.

Why is this happening? And is there a way to avoid it?

2 Likes

Looks like this has been covered already, no surprise there


function addTogether() {
  var len = arguments.length;
  var a = arguments[0];
  var b = arguments[1];
  var isNum = function(arg) { return Number.isFinite(arg); };
  if (len === 1 && isNum(a)) {
    return function(x) {
      if (isNum(x)) {
        return a + x;
      }
    };
  }
  else if (len === 2 && isNum(a) && isNum(b)) {
    return a + b;
  }
}

3 Likes

I’ve edited the basic solution to include more than 2 inputs with a loop.

function addTogether() {
  var checkNum = function(num) {
    if (typeof num !== 'number') {
      return undefined;
    } else {
      return num;
    }
  };
  var total = 0;
  if (arguments.length > 1) {

for (var i = 0; i < arguments.length; i++) {
  var a = checkNum(arguments[i]);
  var b = checkNum(arguments[i + 1]);
  if (a === undefined || b === undefined) {
    return undefined;
  } else {
  total = arguments[i] + arguments[i +1];
  return total;
  }
 }


} else {
  var oneArg = arguments[0];
  if (checkNum(oneArg)) {
  return function(arg2) {
     if (oneArg === undefined || 
 checkNum(arg2) === undefined) {
     return undefined;
     
   } else {
     return oneArg + arg2;
   }
   };
   }
  }

}


addTogether(2, '3');
1 Like

I approached the problem a little differently. I’m not sure if it’s as elegant, but it works! Thoughts?


function addTogether() {
  var args = [].slice.call(arguments);
  if (arguments.length > 1 && args.filter(function(x){return typeof x === "number";}).length === 2) {
    return arguments[0] + arguments[1];
  } else if (arguments.length === 1 && typeof arguments[0] === "number") {
    var prev = arguments[0];
    return function(num) {
      if (typeof num === "number")
      return prev + num;
    };
  }
}

addTogether(2)([3]);
1 Like

a short-liner solution:

function addTogether() {
  'useversion: 6';
  if (arguments.length > 1 && Array.from(arguments).every(item => typeof item === "number") ) {
    return Array.from(arguments).reduce((acc, val) => acc + val);
  } 
  if (arguments.length === 1 && typeof arguments[0] === "number") {
    return addTogether.bind(null, arguments[0]);
  }
}

addTogether(2, "3");
1 Like

My recursive solution! :smiley:

function addTogether() {
  const [a, b] = arguments;

  if (typeof a !== 'number' || (b && typeof b !== 'number')) {
    return undefined;
  }

  if (b) {
    return a + b;
  }

  return c => addTogether(a, c);
}
17 Likes
> function addTogether() {

  function addTwoAnd(x) {
     return function(y) {

       if (typeof x !== 'number' || typeof y !== 'number') {
        return undefined;
      }

      return x + y;
    };
  }

  var addTwo = addTwoAnd(arguments[0]);

  if (typeof arguments[0] !== 'number') {
    return undefined;
  }else
   if (arguments.length > 1) {
     return addTwo(arguments[1]);
    }else 
    return addTwo;
}
addTogether("http://bit.ly/IqT6zt");

One test case fails for my code. Kindly let me know why?
It returns ‘undefined’ (which is expected output), still the case fails.

function addTogether(x) {
if (typeof(x) !== ‘number’)
return undefined;
var args = Array.from(arguments);

if(args.length > 1)
{
if (typeof args[1] !== ‘number’)
return undefined;
else
return x + args[1];
}
else
return function(y){
return x+y;
};
}

function addTogether() {
  let params = [].slice.call(arguments);
  
  if(!params.every(param => typeof param === 'number')) {
    return undefined
  }
  
  if(params.length > 1) {
    return params.reduce((acc, cur) => acc + cur)
  } else {
    let firstParam = arguments[0],
        addOneMore = function(secondParam) {
          return addTogether(firstParam, secondParam);
        };
    return addOneMore
  }
  
  return params
}

addTogether(2);

function addTogether() {
  var a = Array.from(arguments);
  function nan(n){
    return typeof n != 'number';
  }
  return (a.length == 2) ?
              (nan(a[0]) || nan(a[1])) ? undefined : a[1] + a[0]
             :(nan(a[0])) ? undefined : (function(n){ return (nan(n)) ? undefined : n+a[0];});
}

addTogether("http://bit.ly/IqT6zt");

Can someone please explain this to me? I cannot wrap my head around how to access the second argument if there is only one passed to the function. For example, in the callback addTogether(2)(3) how would I access the (3)? Arguments[1] does not do it cause it’s not a second argument. Any help would be appreciated.

4 Likes

@TeeJay let’s break the function call

addTogether(2)(3) is equivalent to below
var fr = addTogether(2)
fr(3)

You can access the second argument (i.e 3) in the function you return when only one argument (i.e. 2) is passed to addTogether.

@sh4hidkh4n I still don’t understand but thank you for trying to explain. I will continue to look trough different solutions to try to understand. Are the any resources that I could read to learn more about this particular concept?

1 Like

Check about how functions are used like variables : http://ryanchristiani.com/functions-as-first-class-citizens-in-javascript/ and anonymous functions http://helephant.com/2008/08/23/javascript-anonymous-functions/

1 Like

Help! Not qualifying for the last test case, even though it returns undefined. Can pls anyone tell me what’s wrong.

function addTogether() {
      
      var args = [].slice.call(arguments);
      var und;
      //console.log(args);
      
      if(args.length > 1) {
        var sum = 0 ;
        
        for(var i in args) {
          if( typeof args[i] === 'number' ) {
            sum += args[i];
          } else {
            return und;
          }
        }
        return sum;
      } else {
        
        if( typeof args[0] === 'number' ) {
          //console.log(args[0] + "here");
          return function(n){
            if(typeof n === 'number') {
              return n + args[0];
            } else {
              return typeof undeclared;
            }
          };
        }
      }
      return und;
    }

    addTogether(2)([3]);