Convert numbers from base X to base Y I recently wrote a piece of code to convert between two bases of X, (Where 26 > X > 0). I was mighty proud that I did this. And then I started wondering, am I using modern coding conventions/practices?

The code can be found here.

And some sample outputs are shown:

// syntax: convertBase(input, inputBase, outputBase)
convertBase("10", 10, 11) // "a"
convertBase("3", 10, 3)   // "10"
convertBase("4", 10, 3)   // "11"


The full code is here:

function convertBase(inNumber, inBase, outputBase) {
  var result = [];
  if (typeof inNumber !== "number" &amp;&amp; typeof inNumber !== "string") {
    throw new Error("You input is not a number or a string.");
  }
  var encodings = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"];
  if (typeof inNumber === "number") {
    inNumber = JSON.stringify(inNumber);
  }
  if (inBase === outputBase) {
    return inNumber;
  }
  inNumber = inNumber.toLowerCase();
  inNumber = inNumber.split("").map(function(item) {
    return encodings.indexOf(item);
  });
  inNumber = inNumber.reverse();
  inNumber = inNumber.map(function(item, index) {
    return item * Math.pow(inBase, index);
  });
  var res = 0;
  inNumber.forEach(function(item) {
    res += item;
    return;
  });
  var ones = res % outputBase;
  var remainder = (res - res % outputBase) / outputBase;
  result.unshift(ones);
  var left = remainder &gt; 1;
  while (left) {
    var ones = remainder;
    var remainder = (remainder - remainder % outputBase) / outputBase;
    result.unshift(ones);
    var left = remainder &gt; 1;
  }
  return result.map(function(item) {
    return encodings[item];
  }).join("");
}
;
Bug

I tried converting "10' from base 10 to base 2 (i.e. binary) and the output was 250, which is invalid for a base 2 number.

Also, when I ran convertBase("3", 10, 3) the output was 0, not "10"

Your Question


  am I using modern coding conventions/practices?


Originally, before I added the javascript tag, this question only had the ecmascript-6 tag. I don't see many features of es-6 in your code, like let and const, arrow functions, default parameters, etc. So judging from an ecmascript-6 point-of-view, I would say No. See the rewrite below which utilizes those features.



const convertBase = (inNumber, inBase = 10, outputBase = 10) =&gt; {
  let result = [];
  if (typeof inNumber !== "number" &amp;&amp; typeof inNumber !== "string") {
    throw new Error("You input is not a number or a string.");
  }
  const encodings = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"];
  if (typeof inNumber === "number") {
    inNumber = JSON.stringify(inNumber);
  }
  if (inBase === outputBase) {
    return inNumber;
  }
  inNumber = inNumber.toLowerCase();
  inNumber = inNumber.split("").map(item =&gt; encodings.indexOf(item));
  inNumber = inNumber.reverse();
  inNumber = inNumber.map((item, index)  =&gt; item * Math.pow(inBase, index));
  let res = 0;
  inNumber.forEach(item =&gt; res += item);
  let ones = res % outputBase;
  let remainder = (res - res % outputBase) / outputBase;
  result.unshift(ones);
  let left = remainder &gt; 1;
  while (left) {
    ones = remainder;
    remainder = (remainder - remainder % outputBase) / outputBase;
    result.unshift(ones);
    left = remainder &gt; 1;
  }
  return result.map(item =&gt; encodings[item]).join("");
};
console.log('convertBase("10", 10, 11):',convertBase("10", 10, 11))




Re-declarations

The code inside the while loop contains variable declarations for variables declared outside the loop:


var ones = res % outputBase;
var remainder = (res - res % outputBase) / outputBase;
result.unshift(ones);
var left = remainder &gt; 1;
while (left) {
  var ones = remainder;
  var remainder = (remainder - remainder % outputBase) / outputBase;
  result.unshift(ones);
  var left = remainder &gt; 1;
}



While the Javascript engine won't "chuck a wobbly1"2 (though somebody who has to update your code might), those assignment statements inside the while loop could exist without the var keyword, and for the sake of readability, probably should not have var at the beginning.

Simplification

The first versions of Ecmascript (i.e. 1 and 5) have had parseInt() and Number.prototype.toString(), which should be enough to implement the desired functionality (though note that the supported base values are 2-36, not 0-26).



const convertBase = (inputNumber, inputBase = 10, outputBase = 10) =&gt;
  parseInt(inputNumber, inputBase).toString(outputBase);

console.log('convertBase("10", 10, 11):', convertBase("10", 10, 11)); // "a"
console.log('convertBase("3", 10, 3):', convertBase("3", 10, 3)); // "10"
console.log('convertBase("4", 10, 3):', convertBase("4", 10, 3)); // "11"
console.log('convertBase(10, 10, 2):', convertBase(10, 10, 2)); // "1010"




1http://spencertipping.com/js-in-ten-minutes/js-in-ten-minutes.pdf
2https://english.stackexchange.com/a/129277/213844