patternjavascriptModerate
Simple object-oriented calculator
Viewed 0 times
orientedobjectsimplecalculator
Problem
After studying several ways of doing OOP in JavaScript I think I finally came up with one that seems OK to me. Is it okay? Do you see some problems I can face by using OOP in JavaScript like this?
JSFiddle test
`var Operators = (function ($, self) {
var self = {};
//private
var IPT_X = '#x';
var IPT_Y = '#y';
//public
self.x = 0;
self.y = 0;
//public
self.showOperators = function() {
//use of a private property (IPT_X) and a public property (this.x)
$(IPT_X).val(self.x);
$(IPT_Y).val(self.y);
};
self.clean = function() {
self.x = 0;
self.y = 0;
// call to a local public method
self.showOperators();
};
self.updateOperators = function(_x, _y) {
// use of a public property
self.x = _x;
self.y = _y;
};
self.clean();
return self;
//Module dependencies
})(jQuery, {});
var Randomizer = (function(self, math) {
// private
function getRandomNumber() {
return math.round(math.random() * 1000);
};
// keep superior method so we can call it after overriding
self.oldUpdateOperators = self.updateOperators
// public
self.updateOperators = function(_x, _y) {
// call to superior class's method
self.oldUpdateOperators(_x, _y);
// call to method of superior object
self.showOperators();
};
self.populateRandomNumbers = function() {
// call to public local method (this.updateOperators())
// and to a local private method (getRandomNumber()))
self.updateOperators(getRandomNumber(), getRandomNumber());
};
// init
self.populateRandomNumbers();
return self;
})(Operators, Math)
var Operations = (function(self, $) {
//private
var IPT_RES = '#res';
var BTN_SUM = '#sum';
var BTN_SUBTRACT = '#subt';
var BTN_MULTIPLY = '#mult';
var BTN_DIVISION = '#div';
var BTN_CLEAN = '#clean';
var B
JSFiddle test
`var Operators = (function ($, self) {
var self = {};
//private
var IPT_X = '#x';
var IPT_Y = '#y';
//public
self.x = 0;
self.y = 0;
//public
self.showOperators = function() {
//use of a private property (IPT_X) and a public property (this.x)
$(IPT_X).val(self.x);
$(IPT_Y).val(self.y);
};
self.clean = function() {
self.x = 0;
self.y = 0;
// call to a local public method
self.showOperators();
};
self.updateOperators = function(_x, _y) {
// use of a public property
self.x = _x;
self.y = _y;
};
self.clean();
return self;
//Module dependencies
})(jQuery, {});
var Randomizer = (function(self, math) {
// private
function getRandomNumber() {
return math.round(math.random() * 1000);
};
// keep superior method so we can call it after overriding
self.oldUpdateOperators = self.updateOperators
// public
self.updateOperators = function(_x, _y) {
// call to superior class's method
self.oldUpdateOperators(_x, _y);
// call to method of superior object
self.showOperators();
};
self.populateRandomNumbers = function() {
// call to public local method (this.updateOperators())
// and to a local private method (getRandomNumber()))
self.updateOperators(getRandomNumber(), getRandomNumber());
};
// init
self.populateRandomNumbers();
return self;
})(Operators, Math)
var Operations = (function(self, $) {
//private
var IPT_RES = '#res';
var BTN_SUM = '#sum';
var BTN_SUBTRACT = '#subt';
var BTN_MULTIPLY = '#mult';
var BTN_DIVISION = '#div';
var BTN_CLEAN = '#clean';
var B
Solution
First I'd say the existence of jQuery is overkill for the task you have. Vanilla DOM handling can be used for this. Besides, you only appear to use jQuery for handling events and setting the value, nothing
Next would be to isolate the UI code from the logic, separation of concerns. Here, your operation module appears to be aware of the DOM. Your operators are also aware, but why? Random is also aware of the fact that you are to update operators, but isn't random just generating random numbers for you?
To visualize, it should be something like
UI handling code will deal with DOM events and manipulation. Only here we should see DOM related code. Logic will only deal with the business logic, like app-specific stuff. Utils (it's a terrible name) is usually libraries and snippets of code that aid you in your logic but not necessarily bound to your app (like your random number generator).
Another thing to note are your names. We're in a very high-level language, and it's not like space matters (there's minifiers for that). Name your stuff verbosely.
Here's a super simplified version of it:
OOP isn't "a must". It's just one of those paradigms available to you in JavaScript. What is "a must" though is keeping your code simple and maintainable. In your version, I was running around because some piece of code did this, and this in another part. In the code above, I know where DOM-related code happens, where the logic happens, who does what.
addEventListener and input.value can't handle.Next would be to isolate the UI code from the logic, separation of concerns. Here, your operation module appears to be aware of the DOM. Your operators are also aware, but why? Random is also aware of the fact that you are to update operators, but isn't random just generating random numbers for you?
To visualize, it should be something like
-- events -> -- data -->
DOM UI handling code logic utils
<- results -- <- results --UI handling code will deal with DOM events and manipulation. Only here we should see DOM related code. Logic will only deal with the business logic, like app-specific stuff. Utils (it's a terrible name) is usually libraries and snippets of code that aid you in your logic but not necessarily bound to your app (like your random number generator).
Another thing to note are your names. We're in a very high-level language, and it's not like space matters (there's minifiers for that). Name your stuff verbosely.
x and y can mean anything, how about value1 and value2. Your "constants" that hold selectors aren't named to say they contain selectors, but they look like they hold actual references to DOM elements (BTN_CLEAN, but it's not really a button).Here's a super simplified version of it:
// This part can live in another file, and are only about operations.
// No part of this code is aware of the DOM.
var CalculatorOperations = {
add: function(value1, value2) {
return value1 + value2;
},
subtract: function(value1, value2) {
return value1 - value2;
},
multiply: function(value1, value2) {
return value1 * value2;
},
divide: function(value1, value2) {
return value1 / value2;
},
generateRandomNumber: function() {
return (Math.random() * 1000) | 0;
},
};
// This part manages events and uses the operations.
// No part of this code actually does the logic.
(function() {
var input1 = document.getElementById('input-1');
var input2 = document.getElementById('input-2');
var result = document.getElementById('result');
var addButton = document.getElementById('add-button');
var subtractButton = document.getElementById('subtract-button');
var multiplyButton = document.getElementById('multiply-button');
var divideButton = document.getElementById('divide-button');
var clearButton = document.getElementById('clear-button');
var randomButton = document.getElementById('random-button');
function setResult(value) {
result.value = value;
}
function setValue1(value) {
input1.value = value;
}
function setValue2(value) {
input2.value = value;
}
addButton.addEventListener('click', function() {
setResult(CalculatorOperations.add(+input1.value, +input2.value));
});
subtractButton.addEventListener('click', function() {
setResult(CalculatorOperations.subtract(+input1.value, +input2.value));
});
multiplyButton.addEventListener('click', function() {
setResult(CalculatorOperations.multiply(+input1.value, +input2.value));
});
divideButton.addEventListener('click', function() {
setResult(CalculatorOperations.divide(+input1.value, +input2.value));
});
clearButton.addEventListener('click', function() {
setValue1('');
setValue2('');
setResult('');
});
randomButton.addEventListener('click', function() {
setValue1(CalculatorOperations.generateRandomNumber());
setValue2(CalculatorOperations.generateRandomNumber());
});
}());
X:
Y:
Res:
OOP isn't "a must". It's just one of those paradigms available to you in JavaScript. What is "a must" though is keeping your code simple and maintainable. In your version, I was running around because some piece of code did this, and this in another part. In the code above, I know where DOM-related code happens, where the logic happens, who does what.
Code Snippets
-- events -> -- data -->
DOM UI handling code logic <-> utils
<- results -- <- results --Context
StackExchange Code Review Q#114933, answer score: 11
Revisions (0)
No revisions yet.