Exercise: Two Additions

Exercise 1 Easy

Prerequisites for the exercise

  1. JavaScript Modules — Basics

Objective

Create a program to compute the sum of two binary numbers or two hexadecimal numbers, both given in string format.

Description

You are working on an application that operates with strings containing binary integers or hexadecimal integers (without any prefixes like 0b or 0x).

One particular task in the application requires the ability to add two binary or hexadecimal strings to one another and then return the output in the same format.

In this exercise, you have to create a program that abides by the following description.

Create two modules, each with a public add() function; one to work with binary strings and one to work with hexadecimal strings. Note that both the functions must be called add().

Then create a main module, referring to both of these modules, that prompts the user to select which addition to perform via a browser prompt dialogue and then performs the corresponding addition on two input numbers.

The initial input prompt meant for obtaining the type of addition desired works as follows:

  • 'bin' means a binary string addition while 'hex' means an addition in the hexadecimal format.
  • Any other input should lead to an alert message, saying 'Invalid addition type!', before finally ending the program.

Following this initial prompt, supposing that the correct input is given, the program should ask for two further inputs that represent the numbers to be added together.

After each input, if the entered value is not valid for the underlying number format, make the alert 'Invalid number entered!' and terminate the program.

In the end, once everything works fine, the given numbers should be added together, and the result output in the same format in which the numbers were given.

Here's a live example for you to better understand the program:

Live Example

View Solution

New file

Inside the directory you created for this course on Advanced JavaScript, create a new folder called Exercise-1-Two-Additions and put the new HTML file solution files for this exercise within it.

Solution

Let's start coding the solution.

First, let's get done with the creation of two modules corresponding to the two different types of additions possible in our program, each with its own exported add() function.

The names we'll choose for our modules are: binary.js and hex.js.

Following are the definitions of add() in both these modules:

binary.js
export function add(a, b) {
   return (parseInt(a, 2) + parseInt(b, 2)).toString(2);
}
hex.js
export function add(a, b) {
   return (parseInt(a, 16) + parseInt(b, 16)).toString(16);
}

First, parseInt() is used to parse numbers out of the given strings a and b, and then toString() is used to convert the sum back into the same string representation for the underlying format.

Learn more about the parseInt() function in JavaScript Numbers — Basics — parseInt().

With this done, now let's create our main script, having the name index.js, where we'll import both these modules and implement the logic of our program.

Here's the code of the main script thus far:

index.js
import { add as binaryAdd } from './binary.js';
import { add as hexAdd } from './hex.js';

Since both the modules export the same name add, we have to use name aliases in the import to be able to use both the functions without name collisions.

The add() function from the binary.js module is aliased as binaryAdd() while the one from hex.js is aliased as hexAdd().

So far, so good.

Now, finally it's time to start working on our main program.

Step one is to make the input prompt, asking the user to enter the type of addition desired. For this, obviously, we'll use the prompt() function in JavaScript.

Its return value will be saved in a variable type. This variable will be tested in a conditional for validity, i.e. it should either be 'bin' or 'hex' (as per the description of the exercise) and the program continued only if it's valid.

Here's the code we get thus far:

index.js
import { add as binaryAdd } from './binary.js';
import { add as hexAdd } from './hex.js';

var type = prompt(`Addition type ('bin' for binary; 'hex' for hexadecimal):`);

if (type !== 'bin' && type !== 'hex') {
   alert('Invalid addition type.');
}
else {
   // The type is valid.
}

Let's now turn our attention to the else block here, which signifies that the entered type was indeed valid.

With a valid type, the next step is to obtain the two numbers to be added.

However, this ain't that easy; the exercise's description clearly states that if the entered number is invalid for the corresponding format, then an alert should be made before ending the program.

So, we need some way to verify that a given number (actually a string) is valid for the chosen type.

For instance, if the type entered was 'bin', then the string '101' is valid (since it contains only the characters 1 and 0) but the string '102' is NOT (a binary number can't have '2' in it). Similarly, for the type 'hex', the string 'ffe' (or 'FFE') is valid but 'ffx' is NOT (a hexadecimal number can't contain 'x').

Before we do anything, since the validity of a given string for a given format is a concern of that format, we'll define a function isValid() in both the modules binary.js and hex.js to determine if a given string is a valid binary string or hexadecimal string, respectively.

To implement the checks, we'll use regular expressions.

Here's the extension to both the module files:

binary.js
export function add(a, b) { /* ... */ }

export function isValid(str) {
   return /^[01]+$/.test(str);
}
hex.js
export function add(a, b) { /* ... */ }

export function isValid(str) {
   return /^[0-9a-fA-F]+$/.test(str);
}

Now, we shall import both these functions into our main script, obviously with name aliases:

index.js
import { add as binaryAdd, isValid as binaryIsValid } from './binary.js';
import { add as hexAdd, isValid as hexIsValid } from './hex.js';

var type = prompt(`Addition type ('bin' for binary; 'hex' for hexadecimal):`);

if (type !== 'bin' && type !== 'hex') {
   alert('Invalid addition type.');
}
else {
   // The type is valid.
}

Back to the else block now that we have a way to verify that a given string is valid for a given format.

Because the format is determined by the user, 'bin' or 'hex', the concrete isValid() function to call (binaryIsValid() or hexIsValid()) has to be determined at runtime. We have two options to do so:

  1. Use a conditional to select the function corresponding to type (defined above).
  2. Use an object to map the value of type to a corresponding function.

Due to its simplicity and brevity, we'll go with the second choice.

Here's the code we get with this approach:

index.js
import { add as binaryAdd, isValid as binaryIsValid } from './binary.js';
import { add as hexAdd, isValid as hexIsValid } from './hex.js';

const isValidMap = {
bin: binaryIsValid,
hex: hexIsValid,
}; var type = prompt(`Addition type ('bin' for binary; 'hex' for hexadecimal):`); if (type !== 'bin' && type !== 'hex') { alert('Invalid addition type.'); } else {
var isValid = isValidMap[type];
var a = prompt('Enter number 1:');
if (!isValid(a)) {
alert('Invalid number entered!');
}
else {
var b = prompt('Enter number 2:');
if (!isValid(b)) {
alert('Invalid number entered!');
}
else {
// Everything's fine.
} } }

The isValidMap constant maps a given type, 'bin' or 'hex', to a concrete isValid() function, either binaryIsValid() or hexIsValid(); hence, the name 'isValidMap'.

Besides this, the body of the else block in line 14 is fairly easy to follow — it gets a concrete isValid() function, obtains the first number, validates it using this function, and ends the program if it ain't valid, and repeats this process for the second number.

The else block in line 25 denotes the case where our program has gotten all correct inputs. Hence, here we must compute the sum of the given numbers and output it as described in the exercise.

This is done below in lines 31 - 32:

index.js
import { add as binaryAdd, isValid as binaryIsValid } from './binary.js';
import { add as hexAdd, isValid as hexIsValid } from './hex.js';

const isValidMap = {
   bin: binaryIsValid,
   hex: hexIsValid,
};

const addMap = {
bin: binaryAdd,
hex: hexAdd,
}; var type = prompt(`Addition type ('bin' for binary; 'hex' for hexadecimal):`); if (type !== 'bin' && type !== 'hex') { alert('Invalid addition type.'); } else { var isValid = isValidMap[type]; var a = prompt('Enter number 1:'); if (!isValid(a)) { alert('Invalid number entered!'); } else { var b = prompt('Enter number 2:'); if (!isValid(b)) { alert('Invalid number entered!'); } else {
var add = addMap[type];
alert(add(a, b)); } } }

As with isValidMap which was used to get a concrete isValid() function, the addMap constant is used to get a concrete add() function.

And this completes our exercise.

Live Example

Obtaining numbers variation

In code, often there is more than one way to accomplish a given task. And certain times, there isn't a good or bad way — it's purely a matter of preference as to which one we choose.

This is exactly the case in the code above where we obtain the numbers to be added together.

In the code above, we manually had two variables a and b with the code validating them repeated twice. For such a simple case, having just two inputs to deal with, this wasn't a big issue for us.

But we could've also used a loop to accomplish this as follows:

index.js
// ...
else {
   var isValid = isValidMap[type];
   var nums = [];
   var areNumbersValid = true;

   for (var i = 0; i < 2; i++) {
      var num = prompt(`Enter number ${i + 1}:`);
      if (!isValid(num)) {
         alert('Invalid number entered!');
         areNumbersValid = false;
         break;
      }
      nums.push(num);
   }

   if (areNumbersValid) {
      var add = addMap[type];
      alert(add(...nums));
   }
}

Evidently, this is more code to type but, at least now, there ain't any repetitions.

Keep in mind that this code isn't necessarily better than the previous one — it's purely a matter of preference as to which one we use to solve this exercise.

Live Example