Q:

JavaScript Code Optimization - Creating Reusable Classes

I am new to JavaScript and need help with code optimization. I am pretty sure there are some ways to create "classes" to run my code better and more efficient.
Here is the link to my jsfiddle demo version: JSFiddle Demo
<form id="tyreForm">
<div id="currentTyre">
<h2>Current Tyre Size</h2>

<div id="errorDisplay"></div>

<input type="number" id="sectionWidth"> /
<input type="number" id="aspectRatio"> R
<input type="number" id="rimDiameter">

<p>Sidewall: <span class="output"></span></p>
<p>Width: <span class="output"></span></p>
<p>Diameter: <span class="output" id="fullDiameter"></span></p>
<p>Circumference: <span class="output"></span></p>
<p>Reverse / Mile: <span class="output"></span></p>
</div>

<div id="newTyre">
<h2>New Tyre Size</h2>

<input type="number" id="newSectionWidth"> /
<input type="number" id="newAspectRatio"> R
<input type="number" id="newRimDiameter">

<p>Sidewall: <span class="output"></span></p>
<p>Width: <span class="output"></span></p>
<p>Diameter: <span class="output" id="newFullDiameter"></span></p>
<p>Circumference: <span class="output"></span></p>
<p>Reverse / Mile: <span class="output"></span></p>
</div>
<div id="result">
<h2>Tyre difference</h2>
<p>Diameter Difference(%): <span id="diameterDifference"></span></p>
</div>
        <button type="submit">Calculate</button>
    </form>

document.getElementById('tyreForm').addEventListener('submit', function(e) {
e.preventDefault();

var sw = this.sectionWidth.value;
var ar = this.sectionWidth.value;
var rd = this.sectionWidth.value;

var nsw = this.newSectionWidth.value;
var nar = this.newAspectRatio.value;
var nrd = this.newRimDiameter.value;

/* Form Validation Starts */
var errorDisplay = document.getElementById('errorDisplay');
errorDisplay.style.display = 'block';

if (sw == '' || ar == '' || rd == '') {
    errorDisplay.style.color = "red";
    errorDisplay.textContent = "Error: Please fill all the fields";
    return false;
}

if (sw == 0 || ar == 0 || rd == 0) {
    errorDisplay.style.color = "red";
    errorDisplay.textContent = "Error: Please check your input fields. 0 is     not valid";
    return false;
}
/* Form Validation Finishes */

this.getElementsByClassName("output")[0].textContent = sidewall(sw, ar).toFixed(2);
this.getElementsByClassName("output")[1].textContent = width(sw, ar, rd).toFixed(2);
this.getElementsByClassName("output")[2].textContent = diameter(sw, ar, rd).toFixed(2);
this.getElementsByClassName("output")[3].textContent = circumference(sw, ar, rd).toFixed(2);
this.getElementsByClassName("output")[4].textContent = reverseMile(sw, ar, rd).toFixed(2);

this.getElementsByClassName("output")[5].textContent = sidewall(nsw, nar).toFixed(2);
this.getElementsByClassName("output")[6].textContent = width(nsw, nar, nrd).toFixed(2);
this.getElementsByClassName("output")[7].textContent = diameter(nsw, nar, nrd).toFixed(2);
this.getElementsByClassName("output")[8].textContent = circumference(nsw, nar, nrd).toFixed(2);
this.getElementsByClassName("output")[9].textContent = reverseMile(nsw, nar, nrd).toFixed(2);

var fd = document.getElementById('fullDiameter').textContent;
var nfd = document.getElementById('newFullDiameter').textContent;
document.getElementById('diameterDifference').textContent =   diameterDifference(fd, nfd);
}, false);

/* All functions */
function sidewall(sw, ar) {
 return ((sw * (ar/100)) / 25.4);
}

function width(sw, ar) {
 return (sw / 25.4);
}

function diameter(sw, ar, rd) {
return ((sidewall(sw, ar) * 2) + parseFloat(rd));
}

function circumference(sw, ar, rd) {
return (((((sw * (ar/100)) / 25.4) * 2)+ parseInt(rd)) * 3.14);
}

function reverseMile(sw, ar, rd) {
return (63360 / (((((sw * (ar/100)) / 25.4) * 2)+ parseInt(rd)) * 3.14));
}

function diameterDifference(fd, nfd) {
return fd * nfd; // Just dummy formula
}

The main idea is:

Have two forms where people can enter their tire sizes.
If only the first form filled with data - calculation happens only in the first form
If both forms are filled with data - both forms' calculations are proceeded plus some data is passed to third form

Please check jsfiddle for more information.
Thanks in advance!
Best

A:

You should create a Tyre prototype that takes sectionWidth, aspectRatio, and rimDiameter in the "constructor" and more all of your functions into that prototype. Doing this will simplify the logic of your code and will help you adhere to the principles of DRY (don't repeat yourself).
var Tyre = function(sectionWidth, aspectRatio, rimDiameter) {
    this.sw = sectionWidth;
    this.ar = aspectRatio;
    this.rd = rimDiameter;

    this.isEmpty = function() {
        return this.sw === '' || this.ar === '' || this.rd === '';
    };

    this.isZero = function() {
        return this.sw == 0 || this.ar == 0 || this.rd == 0;
    };

    this.width = function() {
        return this.sw / 25.4;
    };

    this.sidewall = function() {
        return this.width() * this.ar / 100;
    };

    this.diameter = function() {
        return 2 * this.sidewall() + parseFloat(this.rd);
    };

    this.circumference = function() {
        return this.diameter() * Math.PI;
    };

    this.reverseMile = function() {
        return 63360 / this.circumference();
    };

    this.diameterDifference = function(other) {
        return this.diameter() * other.diameter();
    };
};

document.getElementById('tyreForm').addEventListener('submit', function(e) {
    e.preventDefault();

    var currentTyre = new Tyre(this.sectionWidth.value, this.aspectRatio.value, this.rimDiameter.value);

    var newTyre = new Tyre(this.newSectionWidth.value, this.newAspectRatio.value, this.newRimDiameter.value);

    /* Form Validation Starts */
    var errorDisplay = document.getElementById('errorDisplay');
    errorDisplay.style.display = 'block';

    if (currentTyre.isEmpty()) {
        errorDisplay.style.color = "red";
        errorDisplay.textContent = "Error: Please fill all the fields";
        return false;
    }

    if (currentTyre.isZero()) {
        errorDisplay.style.color = "red";
        errorDisplay.textContent = "Error: Please check your input fields. 0 is not valid";
        return false;
    }
    /* Form Validation Finishes */

    this.getElementsByClassName("output")[0].textContent = currentTyre.sidewall().toFixed(2);
    this.getElementsByClassName("output")[1].textContent = currentTyre.width().toFixed(2);
    this.getElementsByClassName("output")[2].textContent = currentTyre.diameter().toFixed(2);
    this.getElementsByClassName("output")[3].textContent = currentTyre.circumference().toFixed(2);
    this.getElementsByClassName("output")[4].textContent = currentTyre.reverseMile().toFixed(2);

    if (newTyre.isEmpty() || newTyre.isZero())
        return;

    this.getElementsByClassName("output")[5].textContent = newTyre.sidewall().toFixed(2);
    this.getElementsByClassName("output")[6].textContent = newTyre.width().toFixed(2);
    this.getElementsByClassName("output")[7].textContent = newTyre.diameter().toFixed(2);
    this.getElementsByClassName("output")[8].textContent = newTyre.circumference().toFixed(2);
    this.getElementsByClassName("output")[9].textContent = newTyre.reverseMile().toFixed(2);

    document.getElementById('diameterDifference').textContent = currentTyre.diameterDifference(newTyre);
}, false);

