Skip to main content
6 of 8
deleted 36 characters in body
Jamal
  • 34.9k
  • 13
  • 133
  • 237

Simple object-oriented calculator - part 3

This question is an improvement I did based on recommendations from these other questions:

Simple object-oriented calculator

Simple object-oriented calculator - follow-up

To those looking this question first I'm trying to find a correct OOP model I can use in JS. I initially found a very different solution from what's normally done and I received lots of help from some of the good guys here.

And I guess I'm finally coming to grips with it. Please take a look.

JSFiddle

 function ViewBase() {

    Object.defineProperty(this, "parse", { 
        value: function() {
            for(prop in this) 
                this[_.camelCase(prop)] = $('#' + this[prop]);
        },
        writable: true,
        enumerable: false
           
    });

};

// View class mirroring html components
function ViewCalc () {

    this.IPT_X = 'x';
    this.IPT_Y = 'y';
    this.IPT_RES = 'res';
    this.BTN_SUM =  'sum';
    this.BTN_SUBTRACT =  'subt';
    this.BTN_MULTIPLY =  'mult';
    this.BTN_DIVISION =  'div';
    this.BTN_CLEAN =  'clean';
    this.BTN_RAND =  'rand';
    this.parse();

};
ViewCalc.prototype = new ViewBase();

function Operands() {

    // connect view to the base business class
    this.view = new ViewCalc();

    //public
    this.x = 0;
    this.y = 0;

    //public
    this.showOperands = function() {

        //use of a private property (IPT_yyX) and a public property (this.x)
        this.view.iptX.val(this.x);
        this.view.iptY.val(this.y);
    };

    this.clean = function() {
        this.x = 0;
        this.y = 0;

        // call to a local public method 
        this.showOperands();
    };

    this.updateOperands = function(x, y) {
        // use of a public property
        this.x = x;
        this.y = y;
    };

    this.clean();

};

function Randomizer() {

    // private
    function getRandomNumber() {
        return Math.round(Math.random() * 1000);
    };

    this.updateOperands = function(x, y) {
        // call to superior class's method
        Randomizer.prototype.updateOperands.call(this, x, y);
        // call to method of superior object
        this.showOperands();
    };

    this.populateRandomNumbers = function() {
        // call to public local method (this.updateOperands())
        // and to a local private method (getRandomNumber()))
        this.updateOperands(getRandomNumber(), getRandomNumber());
    };

    // init
    this.populateRandomNumbers();

};
Randomizer.prototype = new Operands();

function Operations() {
    //public
    this.sum = function() {
        // call to 2 local private methods
        showRes(doSum());
    };

    this.subtract = function() {
        showRes(doSubtraction());
    };

    this.multiply = function() {
        showRes(doMultiplication());
    };

    this.division = function() {
        showRes(doDivision());
    }; 

    var self = this;

    // private
    function doSum() {
        return self.x + self.y;
    };

    function doSubtraction() {
        return self.x - self.y;
    };

    function doMultiplication() {
        return self.x * self.y;
    };
 
    function doDivision() {
        return self.x / self.y;
    };

    function showRes(val) {
        self.view.iptRes.val(val);
    };

    // init
    this.view.btnSum.on('click', function() { self.sum() });
    this.view.btnSubtract.on('click', function() { self.subtract() });
    this.view.btnMultiply.on('click', function() { self.multiply() });
    this.view.btnDivision.on('click', function() { self.division() });   
    this.view.btnClean.on('click', function() { self.clean() });
    this.view.btnRand.on('click', function() { self.populateRandomNumbers()     });

};
Operations.prototype = new Randomizer();

var o = new Operations();
<html>
<body>
X: <input id='x'>
<br>
Y: <input id='y'>
<br>
Res: <input id='res'>
<br>
<input id='sum' type='button' value='+'>
<input id='subt' type='button' value='-'>
<input id='mult' type='button' value='*'>
<input id='div' type='button' value='/'>
<input id='clean' type='button' value='C'>
<input id='rand' type='button' value='Rand'>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.10.1/lodash.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>

What I did this time:

From @tkellehe's and @SirPython's answers:

  • I'm realizing that using this self variable is causing more harm than does good. So I reverted to this, new and prototype usage.

From @tkellehe's answer:

  • I remove all _vars from parameters, all private vars will use it from now on. Just there aren't any at the example at the moment.
  • I used Object.define in the View classes so I don't need to use Object.keys anymore.
  • Because I reverted to this, new and prototype usage, override function doesn't work/it's not needed anymore. So I had to use Class.prototype.method.call instead and I don't need a base class anymore or a salvage to not using new. At least at this point.
  • I know loading within context is important and I'll use it. I just don't think it's needed for this example. But that library loading function was really cool.

What still bothers me:

  • I don't like using Class.prototype.method.call. It's too long and too clumsy. Is there a better solution for calling the superior method? Can you make override function work again in this format?
  • In the ViewCall and ViewBase classes, it would be better if I could put this.parse() in the ViewBase class in such a manner that it get called in the moment ViewClass was instatiated. But I couldn't find a way to do it. Does anyone have an idea on how I could do this?