8
\$\begingroup\$

This is code for performing a calculation that should be repeated with different levels and temperatures. I am concerned about the organization of this code as I feel it may contain too many helper functions and seems a little unnecessarily complicated. Only the getCharge() method needs to be exposed to the browser.

There is sample usage of this code after the initial definition.

var hprVessel = function (level, temp) {
/**
* @params {Number} level - Percentage load for HPR 
* @params {Number} temp - temperature of fluid
*/
 var liquidCoefficients = [
 83.4485407734612,
 -0.111449280945489,
 0.000100022560084721,
 -0.00000206240663899928
 ];
 var vaporCoefficients = [
 0.895329190066827, 
 0.016635773286873, 
 -0.0000894924196507015, 
 0.00000206296636296276
 ];
 var vessel = {
 // Vessel-specific Params
 diameter: 1.9583 * level,
 height: 0.2937 * level,
 length: 15.9583 * level,
 // Calculations
 getLiquidVol: function () { 
 var r = this.diameter/2;
 var sectionArea = Math.pow(r, 2) * Math.acos((r - this.height) / r);
 var triangleArea = Math.sqrt(Math.pow(r, 2) - Math.pow((r-this.height), 2))*(r-this.height);
 return (this.length * sectionArea * triangleArea);
 },
 getVesselVol: function () {
 return (Math.PI * Math.pow(this.diameter, 2) * this.length);
 },
 getVaporVol: function () {
 return (vessel.getVesselVol() - vessel.getLiquidVol());
 },
 getLiquidCharge: function (temp) {
 return (vessel.getLiquidVol() * vessel.calcDensity(liquidCoefficients, temp));
 },
 getVaporCharge: function (temp) {
 return (vessel.getVaporVol() * vessel.calcDensity(vaporCoefficients, temp));
 },
 chargeHPR: function (temp) {
 return (1000 + vessel.getLiquidCharge(temp) + vessel.getVaporCharge(temp));
 },
 // Helper functions
 calcDensity: function (regressionCoefs, temp) {
 var liqDensityArray = regressionCoefs.map(function (coef) {
 return coef * Math.pow(temp, regressionCoefs.indexOf(coef));
 });
 return vessel.sum(liqDensityArray);
 },
 sum: function (arr) {
 return arr.reduce( function (prev, current) {
 return (prev + current);
 }
 }
 };
 return {
 getCharge: function() {
 return vessel.chargeHPR(temp);
 }
 };
}
var vessel = hprVessel(1, -30);
var result = vessel.getCharge();
asked Jan 4, 2016 at 22:51
\$\endgroup\$

1 Answer 1

3
\$\begingroup\$
diameter: 1.9583 * level,
height: 0.2937 * level,
length: 15.9583 * level,

It might be wise to actually put these numbers in a constant and naming them appropriately. That way, in the long run, you won't forget what these values are.

return (/* stuff */);

I notice you also use parens in your returns. Unless they're a personal preference, they're actually optional (What do you think this is? PHP? :P)

Now this code appears to benefit more using prototypal inheritance rather than a factory pattern. That's because every time you call hprVessel, it builds an object of functions. With prototypal inheritance, your instance will only hold instance properties, aka "vessel-specific data". The functions will be shared across your vessel instances via the prototype.

Here's a short example:

function HPRVessel(level, temp){
 // Instance data, aka vessel-specific data
 this.temp = temp;
 this.level = level;
 this.diameter = HPRVessel.SOME_CONSTANT * level,
 this.height = HPRVessel.ANOTHER_COSNTANT * level,
 this.length = HPRVessel.YET_ANOTHER_CONSTANT * level,
}
// pseudo-static properties
// Here we append general HPRVessel constants
HPRVessel.liquidCoefficients = [
 83.4485407734612,
 -0.111449280945489,
 0.000100022560084721,
 -0.00000206240663899928
];
HPRVessel.SOME_CONSTANT = 1.9583
HPRVessel.ANOTHER_COSNTANT = 0.2937
HPRVessel.YET_ANOTHER_CONSTANT = 15.9583
// Here, we define shared stuff. Best practice is to just put methods on it.
HPRVessel.prototype.getCharge = function(){
 // Anything on the instance is accessible via `this`
 return this._chargeHPR(this.temp);
};
// Since there's no "private", we use the convention of prefixing `_` to tell
// curious people not to call these methods directly
HPRVessel.prototype._chargeHPR= function(){
 return (1000 + this._getLiquidCharge(this.temp) + this._getVaporCharge(this.temp));
};
// Usage:
var vessel = new HPRVessel(1, -30);
var result = vessel.getCharge();
answered Jan 4, 2016 at 23:45
\$\endgroup\$
3
  • \$\begingroup\$ Good suggestions! If I understand prototypes correctly, should my code be more performant if I wrap the methods with a prototype since they will only be declared once across all instances? \$\endgroup\$ Commented Jan 5, 2016 at 0:27
  • 1
    \$\begingroup\$ It goes a little deeper than just sharing methods. Modern browsers do all kinds of Chicken Voodoo Magic with Just In Time compilers. For instance, many browsers will actually create a compiled machine code level class to represent your object in JavaScript getting you near native execution times. Code using function closures is harder to optimize. Admittedly your code won't exhibit a difference in performance unless it is run in a loop over many iterations or in "spammy" events like mousemove. \$\endgroup\$ Commented Jan 5, 2016 at 3:24
  • \$\begingroup\$ I am expecting to call this function a large number of times in order to perform operations on a pretty big data set so it definitely helps to optimize. \$\endgroup\$ Commented Jan 5, 2016 at 16:43

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.