5
\$\begingroup\$

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" && 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 > 1;
  while (left) {
    var ones = remainder;
    var remainder = (remainder - remainder % outputBase) / outputBase;
    result.unshift(ones);
    var left = remainder > 1;
  }
  return result.map(function(item) {
    return encodings[item];
  }).join("");
}
;
\$\endgroup\$
  • \$\begingroup\$ (Where 26 > X > 0). Base 1 does not seem to have much utility. \$\endgroup\$ – radarbob Apr 30 '18 at 19:18
  • \$\begingroup\$ @radarbob XD no it does not. \$\endgroup\$ – FreezePhoenix Apr 30 '18 at 19:24
2
\$\begingroup\$

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 tag, this question only had the 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 point-of-view, I would say No. See the rewrite below which utilizes those features.

const convertBase = (inNumber, inBase = 10, outputBase = 10) => {
  let result = [];
  if (typeof inNumber !== "number" && 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 => encodings.indexOf(item));
  inNumber = inNumber.reverse();
  inNumber = inNumber.map((item, index)  => item * Math.pow(inBase, index));
  let res = 0;
  inNumber.forEach(item => res += item);
  let ones = res % outputBase;
  let remainder = (res - res % outputBase) / outputBase;
  result.unshift(ones);
  let left = remainder > 1;
  while (left) {
    ones = remainder;
    remainder = (remainder - remainder % outputBase) / outputBase;
    result.unshift(ones);
    left = remainder > 1;
  }
  return result.map(item => 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 > 1;
while (left) {
  var ones = remainder;
  var remainder = (remainder - remainder % outputBase) / outputBase;
  result.unshift(ones);
  var left = remainder > 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) =>
  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

\$\endgroup\$
  • \$\begingroup\$ *frowns* Looks like I didn't debug well. \$\endgroup\$ – FreezePhoenix Apr 29 '18 at 13:23

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.