1
\$\begingroup\$

This is what I came up with, but I'm not sure if:

  • putting it in Class is the best approach
  • multiple repeats (this.val etc.) are acceptable
  • there is a better approach (maybe with constructor)

class UnitChange {
  temperature(val, to) {
    this.val = val;
    this.to = to;
    if (this.to === "toF") {
      return this.val * 1.8 + 32;
    } else {
      return (this.val - 32) / 1.8;
    }
  }
  speed(currentUnit, val, to) {
    this.currentUnit = currentUnit;
    this.val = val;
    this.to = to;
    if (this.to === "tomph") {
       if (this.currentUnit === "kph") {
       return this.val * 0.62;
      } else {
       return this.val * 2.23;
      }
    } else if (this.to === "tokph") {
      if (this.currentUnit === "mph") {
        return this.val * 1.60;
      } else {
        return this.val * 3.6;
      }
    } else if (this.to === "toms") {
    if (this.currentUnit === "kph") {
      return this.val * 0.27;
    } else {
      return this.val * 0.44;
    }
  }
 }
};

let change = new UnitChange();
console.log(change.temperature(8, "toF"));
console.log(change.speed("kph", 100, "tomph"));
\$\endgroup\$

1 Answer 1

3
\$\begingroup\$

A static Object

The class syntax is not very well suited to this type of object use. The object should be a static object, as you would only ever need one instance, and you should not need to instantiate it each time you need to use it.

Reduce complexity

Having to write a conversion from each type of unit means you add a lot of extra code. Say you added a Kelvin Unit to temperatures, your code would need to convert from C => F, C => K, F => C, F=> K, K => C, and K => F. For some types of units this would quickly balloon out of control.

For conversion you always convert to a standard unit, and then convert that value to the unit you want. This reduces the complexity. I would advice you to use SI units, however what units you choice is is irrelevant.

Units have meaning

Be aware that there are limits to some units.

Temperatures have a base of -273.15C, returning a value less than that is meaningless.

The speed of light is the upper limit of speed, however conceptually speeds above this limit can still have meaning.

Why create the converter

A conversion object is by its nature an object of convenience, as the actual computations are trivial and for any computational work should be inline. So when you design such an object, consider how it is to be used. Adding common constants for example, provide aliases

You can also add functionality dynamically, see example that creates direct conversion function, eg the function Units.kmph2mph(kmph) is created dynamically

Example

The example has added a lot of extra functionality, none of it is a must outside your direct conversions, its just to give you some ideas on how these things can be done.

The snippet contains a static object 'Units' created via a self invoking function. It includes some aliases eg unit.F is same as unit.fahrenheit. some constants, and some dynamic functions.

All units are converted to a base unit type (kelvin and meters per second)

Usage as follows

Units.kmph = 100;
const mph = Units.mph;
Units.celsius = 38;
const f = Units.fahrenheit;

//or via direct conversion

const mph = Units.kmph2mph(100);
const f = Units.C2F(38);
const zeroF = Units.K2F(Units.ABSOLUTE_ZERO_K);
Units.C2K(-10000); // will return 0 

Please note I have not tested this snippet and it may contain typos, it is as an example only.

const Units = (() => {
    var tempK = 0;
    var ms = 0; // meters per second
    const secondsPerHour = 60 * 60;
    const zeroC = - 273.15
    const API = {
        /* Temps */
        get fahrenheit(){ return API.celsius * 1.8 + 32},
        get celsius() {return API.kelvin + zeroC},
        get kelvin() {return tempK < 0 ? 0 : tempK },
        set fahrenheit(f) {tempK = (f - 32) / 1.8 - zeroC},
        set celsius(c) {tempK = c - zeroC},
        set kelvin(k) {tempK = k},
        /* Speeds */
        get milesPerHour() {return ms / secondsPerHour / 1600},
        get kilometersPerHour() {return ms / secondsPerHour / 1000},
        get metersPerSecond() {return ms },
        set milesPerHour(mph) {ms = mph * 1600 * secondsPerHour},
        set kilometersPerHour(kmph) {ms = kmph * 1000 * secondsPerHour},
        set metersPerSecond(ms) {ms = ms},
        /* Aliases */ 
        get F() {return API.fahrenheit},
        get C() {return API.celsius},
        get K() {return API.kelvin},
        set F(f) {API.fahrenheit = f},
        set C(c) {API.celsius = c },
        set K(k) {tempK = k },
        get mph() {return API.milesPerHour},
        get kmph() {return API.kilometersPerHour},
        get ms() {return ms},
        set mph(mph) {API.milesPerHour = mph},
        set kmph(kmph) {API.kilometersPerHour = kmph},
        set ms(ms) {ms = ms},
        /* Constants */
        SPEED_OF_LIGHT_MS : 299792458, // ms
        SPEED_OF_SOUND_MS : 343, // ms
        ABSOLUTE_ZERO_K : 0, // K
        MILES_PER_KILOMETER : 1 / 1.6,
        KILOMETERS_PER_MILE : 1 * 1.6,
    };

    // Create direct conversion from alias names using 2 for to. eg F2C
    [["F", "C", "K"], ["kmph", "mph", "ms"]].forEach(type => {
        for(const unitFrom of type) {  // unitFrom must be const or let
            for(const unitTo of type) { // unitTo must be const or let
                if (unitFrom !== unitTo) {
                    API[unitFrom + "2" + unitTo] = function(unit) { 
                        API[unitFrom] = unit; 
                        return API[unitTo];
                    }
                }
            }
        }
    });                    
    return Object.freeze(API); // freeze it so it can not be damaged
})();
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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