I am reviewing some design patterns in JavaScript. My first design pattern is the module pattern. After researching a bit I built the following example:
var CarCostEstimation = (function() {
//Let's imagine script is getting best price from different api's
function getBestMotorCost() {
return 3000;
}
function getBestChasisCost() {
return 1000;
}
function getBestWheelsCost() {
return 400;
}
return {
getEstimatedCost: function() {
var chasisCost = getBestChasisCost();
var motorCost = getBestMotorCost();
var wheelsCost = getBestWheelsCost();
return chasisCost + motorCost + wheelsCost;
}
}
})();
var totalCost = CarCostEstimation.getEstimatedCost();
console.log(totalCost);
I have two doubts:
If the way I am calling the "private" methods, in my public method is the correct one.
If I want to add this CarCostEstimation module to another Estimation module, how would it do it?
For point 2:
var CostEstimation = (function() {
var estimationObject;
function sumDifferentEstimations() {
estimationObject.getEstimatedCost();
}
return {
addEstimationObjetc: function(object) {
estimationObject = object
},
getTotalCost: function() {
return sumDifferentEstimations();
}
}
})();
Another way to define your functions. (I'm also using some ES6 syntax)
const CarCostEstimation = function() {
return {
getBestMotorCost: () => 3000,
getBestChasisCost: () => 1000,
getBestWheelsCost: () => 400,
getEstimatedCost: function() {
const chasisCost = this.getBestChasisCost();
const motorCost = this.getBestMotorCost();
const wheelsCost = this.getBestWheelsCost();
return chasisCost + motorCost + wheelsCost;
}
}
}();
const totalCost = CarCostEstimation.getEstimatedCost();
console.log(totalCost);
To export your function as a module, you could use the export statement from ES6 and import your module using the import statement
https://developer.mozilla.org/en/docs/web/javascript/reference/statements/export
Related
I have the CalculationDesignSingleton.js file, and the CalculationDesignSingleton.test.js which is using Jest to test the file. When I run the test file, I received an error said calculation.getInstance is not a function. Can someone help me? Thank you
CalculationDesignSingleton.js
let calculation = (function () {
let instance;
function createInstance() {
let calculator = new Calculator("I am the instance");
return calculator;
}
return {
getInstance: function () {
if (!instance) {
instance = createInstance();
}
return instance;
}
};
})();
CalculationDesignSingleton.test.js
const calculation = require('../src/Operations/CalculationDesignSingleton');
test('Test Design Pattern Singleton of Calculation', () => {
//I need to test the get results function
const singletonA = calculation.getInstance();
const singletonB = calculation.getInstance();
const isEqual = singletonA === singletonB;
expect(isEqual).toBe(true);
});
Can I get a little advice on my js modules? I'm good with js, but not quite guru status :) Am I refactoring my modules right?
I've been using the js module pattern like this (rough example, I'm just worried about the structure):
sloppy way?
/* Module Code */
var MapModule = (function ($) {
var $_address;
var $_mapContainer;
function loadApi() {
// do something. maybe load an API?
}
function someInternalMethod() {
// do other things
}
var pub = {};
pub.setAddress = function (address) {
$_address = address;
};
pub.getAddress = function () {
return $_address;
};
pub.initialize = function () {
loadApi();
}
})(jQuery);
// usage
MapModule.initialize();
But that usage seems a little sloppy. I like constructors.
I refactored some modules like this:
Better way?
(function ($) {
this.MapModule = function () {
var $_address;
var $_mapSelector;
var $_mapContainer;
function loadApi() {
// do something. maybe load an API?
}
function someInternalMethod() {
$_mapContainer = $($_mapSelector);
// do stuff with the jQ object.
}
var pub = {};
pub.setAddress = function (address) {
$_address = address;
};
pub.getAddress = function () {
return $_address;
};
pub.initialize = function (selector) {
$_mapSelector = selector;
loadApi();
}
}
})(jQuery);
var map = new MapModule();
map.initialize('#mapcontainer');
That usage seems a lot cleaner to me, and it works just fine, but am I going about it properly?
Taking it another step
Say this module does some stuff with a div that wraps Google Maps and jQuery functionality: Any tips on turning that into a jQ plugin so I can use it with a signature like var map = $('mapcontainer').mapModule();
Thanks!
I have modified your snippet and have actually implemented javascript revealing module pattern which gives the opportunity to implement public & private functions using closure.
Hope this will be helpful:
/* Module Code */
var MapModule = (function (module, $, global) {
var $_address;
var $_mapContainer;
// Public functions
function _loadApi() {
// Do something, maybe load an API?
}
function _someInternalMethod() {
// Do other things.
}
function _initialize = function () {
_loadApi();
}
// Private functions
function _setAddress = function (address) {
$_address = address;
};
function _getAddress = function () {
return $_address;
};
$.extend(module, {
loadApi: _loadApi,
someInternalMethod: _someInternalMethod,
initialize: _initialize
});
return module;
})(MapModule || {},this.jQuery, this);
// Usage
MapModule.initialize();
JSFiddle
Just came across this and thought I'd share my approach...
///////////////////////////////
// Module Code
///////////////////////////////
var ExampleModule = (function()
{
////////////////////////////
// Private Properties
////////////////////////////
var whatever = {
data: 'somedata';
};
////////////////////////////
// Private functions
////////////////////////////
function _init()
{
_loadApi();
_bindToUIEvents();
}
function _loadApi()
{
// load an api
}
function _bindToUIEvents()
{
$('#something').on('click', function(){
// Do something cool
});
}
function _getWhatever()
{
return whatever;
}
//////////////////////
// Public API
//////////////////////
return{
init: _init(),
getWhatever: function()
{
return _getWhatever();
}
};
})();
// Usage
ExampleModule.init;
I have JavaScript class which have huge functions which are very difficult to maintain.
The 2 public functions are called at start and then on click. I want to create private functions inside these public functions say break into into some private functions scope to these public methods.
var searchResultView;
var SearchResultView = function () {
me = this;
this.init = function () {
// huge code
}
this.Search = function () {
// huge code
}
}
jQuery(function () {
searchResultView = new SearchResultView();
searchResultView.init();
searchResultView.Search();
}
What will best way to achieve this. I tried to use below approach but i think this nested function will not work well.
var searchResultView;
function searchResultView() {
me = this;
this.init = function () {
var declareControls = function () {}
var addEvents = function () {}
var fillControls = function () {}
declareControls();
addEvents();
fillControls();
}
this.Search = function () {
var validateAndCreateCriteria = function () {
if (!validateAandGetLocation()) {
alert("invalid location");
return false;
}
if (!validateAandGetCategory()) {
alert("choose search type");
return false;
}
var validateAandGetLocation = function () {}
var validateAandGetCategory = function () {}
}
validateAndCreateCriteria();
}
}
jQuery(function () {
searchResultView = new searchResultView();
searchResultView.init();
});
If I understood correctly, you should have the functions something like this:
var foo = (function() {
var privateBar = function() { // private function
},
privatefooBar = function() { // private function
};
return {
publicFoo : function() { //public function
/* use privateBar and privatefooBar functions here */
}
};
})();
Later you can access publicFoo function by using
foo.publicFoo();
But you can't access the inside functions which are privateBar() and privatefooBar() directly because they are private functions.
Updated Fiddle
Breaking up the function is easy:
function f(..) {
// many lines here
return ret_f;
}
if equivalent to
function f {
function f1(..) {
// not so many lines here
}
function f2(..) {
// not so many lines here
}
var ret_f1 = f1(..);
var ret_f2 = f2(..);
// calculate ret_f from ret_f1 and ret_f2
return ret_f;
}
or if you prefer this style using anonymous functions
function f {
var f1 = function(..) {
// not so many lines here
};
var f2 = function(..) {
// not so many lines here
};
var ret_f1 = f1(..);
var ret_f2 = f2(..);
// calculate ret_f from ret_f1 and ret_f2
return ret_f;
}
I fear however your real question is specific to your existing code and is about what useful smaller functions to extract there and how to combine them.
For this one would need to have your full code and understand it. That might be a bit much for this QA format.
I am trying to write a small javascript library as shown below. What I really want is when I call
console.log(tnd().pv);
it should output same number and not generate new number everytime. I know the issue is it calls Math.random everytime I console log. But how can I do so that it outputs same number?
(function () {
var tnd = function() {
return new tnlib();
};
var tnlib = function() {
this.version = function(){
console.log('1.0');
};
this.pv = Math.random()*10000000000000000;
};
if(!window.tnd) {
window.tnd = tnd;
}
})();
Don't execute Math.random() on each invocation of tnlib, but as a static variable:
(function () {
function tnd() {
return new tnlib();
}
function tnlib() {
}
tnlib.prototype.version = function(){
console.log('1.0');
};
tnlib.prototype.pv = Math.random()*10000000000000000;
if (!window.tnd) {
window.tnd = tnd;
}
}());
(or, if you really need to make pv an instance property):
var staticPv = Math.random()*10000000000000000;
function tnlib() {
this.pv = staticPv;
…
}
In the following code, I want to be able to call bindClickEvents() like so:
App.Utils.Modal.bindClickEvents();
However, I don't understand the syntax necessary to do this.
Current code:
var App = new Object;
App.Modal = {
bindClickEvents: function() {
return $('a.alert-modal').click(function(e) {
return console.log('Alert Callback');
});
}
};
$(document).ready(function() {
return App.Modal.bindClickEvents();
});
You can do it in one go:
var App = {
Modal : {
bindClickEvents : function () {/* ... */}
}
}
or if you want to break that up to separate steps:
var App = {};
App.Modal = {};
Modal.bindClickEvents = function () {/* ... */};
BTW, in reference to your original question title, this is not object chaining. This is object composition. Object chaining is being able to call methods in an object multiple times in a single statement.
Is this what you're trying to do?
var App = {};
App.Utils = {};
App.Utils.Modal = {
bindClickEvents: function() {
return $('a.alert-modal').click(function(e) {
return console.log('Alert Callback');
});
}
};
$(document).ready(function() {
return App.Utils.Modal.bindClickEvents();
});
Prefer the object literal syntax to the Object constructor; some authors go so far as to call the latter an anti-pattern
Here's the simplest way to set up App.Utils.Modal.bindClickEvents();
var App = {
Utils: {
Modal: {
bindClickEvents: function() {
return $('a.alert-modal').click(function(e) {
return console.log('Alert Callback');
});
}
}
}
};
Or you can piece it together one step at a time:
var App = {};
App.Utils = {};
App.Utils.Modal = {};
App.Utils.Modal.bindClickEvents = function() {
return $('a.alert-modal').click(function(e) {
return console.log('Alert Callback');
});
};