Node Module Inheritance - javascript

I wrote the below listed module for an ExpressJS application. I now need to create a similar module with about 3 changed methods, and a few different instance variables. My plan is to create a superclass that has all the common (call it Common.js) and then require it for the two or more subclasses.
I generalized pointer to a tutorial might help me, but here are my specific questions:
the requires will be common, I suppose I put them in Common.js,
right?
I assume I should promote as many instance variables (the subclasses) into Common as possible?
The following could be a template fro the subclasses, with the Object.create coming at the top of the file
SubClass snippet:
var Common = require("./Common");
SubClass.prototype = Object.create(Common.prototype);
SubClass.prototype.subMethod = function() {....}
and also I assume that any submethod can refer to variables in the superclass, as well as new variables in the subclass, with as this.variableName,
BTW, how would I create new subClass instance variables?
Here is my original Code:
var _ = require('lodash');
var path = require('path');
var fs = require('fs');
var tools = require("../tools/tools");
var Job = require("./falconJob");
var Batch = function (ticket) {
this.counts = [];
this.maxes = [];
this.errors = [];
this.done = [];
this.jobs = 0;
this.started = Date.now();
this.ended = Date.now();
this.jobBatch = {};
this.ticket = ticket;
this.batchRoot = null;
}
Batch.prototype.setup = function (frameList, req, next) {
this.group(frameList);
this.makeRoot(req, next);
}
Batch.prototype.group = function (list) {
_.forEach(list, function (obj) {
if (this.jobBatch[obj.type] == undefined) {
this.jobBatch[obj.type] = [];
}
this.jobBatch[obj.type].push(obj);
}, this);
};
Batch.prototype.makeRoot = function (req, next) {
var config = global.app.settings.config;
this.batchRoot = path.join(config.JobsPath, this.ticket);
var self = this;
fs.mkdir(this.batchRoot, function (err) {
if (err) return next(err);
var mapInfoFile = path.join(self.batchRoot, "MapInfo.json");
var mapInfo = {
Date: (new Date()).toISOString(),
Version: global.manifestVID,
Zoom: req.body.Zoom,
CenterLat: req.body.CenterLat,
CenterLon: req.body.CenterLon
};
fs.writeFile(mapInfoFile, tools.pretty(mapInfo), function (err) {
if (err) return next(err);
return next(null);
});
});
};
Batch.prototype.spawn = function () {
_.forEach(this.jobBatch, function (files, key) {
var job = new Job(key, files, this.batchRoot, this.ticket, this);
this.begin(job);
job.exec();
}, this);
};
Batch.prototype.count = function () {
var sum = 0;
for (var key in this.counts) {
sum += this.counts[key];
}
return sum;
}
Batch.prototype.total = function () {
var sum = 0;
for (var key in this.maxes) {
sum += this.maxes[key];
};
return sum;
}
Batch.prototype.fails = function () {
var sum = 0;
for (var key in this.errors) {
sum += (this.errors[key]) ? 1: 0;
};
return sum;
}
Batch.prototype.finished = function () {
var keylist = Object.keys(this.done);
if (keylist.length == 0) return false;
for (var key in this.done) {
if (this.done[key] == false) return false;
};
if (this.jobs != 0) return false;
return true;
}
Batch.prototype.rate = function () {
var speed = (this.count() * 1000) / (this.ended - this.started); // tiles / second
return speed;
}
Batch.prototype.begin = function (job) {
var type = job.type;
this.jobs++;
this.counts[type] = 0;
this.maxes[type] = 0;
this.errors[type] = false;
this.done[type] = false;
}
Batch.prototype.end = function (job) {
type = job.type;
this.jobs--;
this.errors[type] = job.errors;
this.done[type] = true;
}
Batch.prototype.update = function (status) {
type = status.layer;
this.ended = Date.now();
this.counts[type] = status.tilesCount;
this.maxes[type] = status.tilesMax;
this.done[type] = status.done;
}
module.exports = Batch;

I am surprised, no one answered. Well I have a solution, and a few tips. First, read the Mozilla developer page about an introduction to javascript inheritance: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Introduction_to_Object-Oriented_JavaScript
Here is how I structured my "sub-module" which I can just require in and it will pull in the super-module, and then subclass it.
var _ = require('lodash'); // require any additional modules that your sub module needs
var BatchRoot = require('./Batch'); // require the super-module with the superclass
var Job = require("./falconJob"); // another module that I need
var Batch = function (ticket) {
BatchRoot.call(this, ticket); // The superclass constructor takes "ticket" as a param
// define new subclass instance variables here, e.g. this.foobar = 33;
}
Batch.prototype = new BatchRoot(); // This does the subclassing
Batch.prototype.constructor = BatchRoot; // MDN says to do this to correct the constructor pointer because it points to Batch
// this is a new subclass function, notice that I use Job which is only defined here
Batch.prototype.spawn = function () {
_.forEach(this.jobBatch, function (files, key) {
var job = new Job(key, files, this.batchRoot, this.ticket, this);
this.begin(job);
job.exec();
}, this);
};
module.exports = Batch;

Related

arguments.length run the function if 3 arguments are passed, otherwise throw an error object

TasksI need to modify the displaySortedTaskList function so that it runs if there are 3 arguments passed, and throws an error object with a message if there aren't 3 arguments passed. My attempt:
"use strict";
var sortTaskList = function(tasks) {
var isArray = Array.isArray(tasks);
if (isArray) {
tasks.sort();
}
return isArray;
};
var displaySortedTaskList = function(tasks, div, handler) {
if(arguments.length = Function.length){
var html = "";
var isArray = sortTaskList(tasks);
if (isArray) {
//create and load html string from sorted array
for (var i in tasks) {
html = html.concat("<p>");
html = html.concat("<a href='#' id='", i, "'>Delete</a>");
html = html.concat(tasks[i]);
html = html.concat("</p>");
}
div.innerHTML = html;
// get links, loop and add onclick event handler
var links = div.getElementsByTagName("a");
for (var i = 0; i < links.length; i++) {
links[i].onclick = handler;
}
}
} else {document.getElementById("message").innerHTML = "The displaySortedTaskList function of the tasklist library requires three arguments"}
};
var deleteTask = function(tasks, i) {
var isArray = sortTaskList(tasks);
if (isArray) { tasks.splice(i, 1); }
};
var capitalizeTask = function(task) {
var first = task.substring(0,1);
return first.toUpperCase() + task.substring(1);
};
You might use rest parameters and check whether the length of the array is 3:
var displaySortedTaskList = function(...args) {
if (args.length !== 3) {
document.getElementById("message").textContent = "The displaySortedTaskList function of the tasklist library requires three arguments";
return;
// or `throw new Error('not enough args')` ?
}
const [tasks, div, handler] = args;
// rest of your code
(note that you should assign to .textContent when inserting text - .innerHTML is appropriate when inserting HTML markup, which is not the case here)
Live snippet:
var displaySortedTaskList = function(...args) {
if (args.length !== 3) {
return console.log('error');
}
console.log('rest of the code');
}
displaySortedTaskList('foo', 'bar');
displaySortedTaskList('foo', 'bar', 'baz');
displaySortedTaskList('foo', 'bar', 'baz', 'buzz');

JavaScript object inheritance issue

I'm a beginner with JavaScript Objects and Prototypes and trying to develop my first " multi-level inherited" JS Objects, an unexpected issue came up.
This is my code:
var Utils = function () {};
Utils.prototype = {
sayHelloGeneral: function(){
console.log('hello');
}
};
var FormTools = function () {
Utils.call(this);
this.fields = [];
};
FormTools.prototype = Object.create(Utils.prototype);
FormTools.prototype.constructor = FormTools;
FormTools.prototype.sayHelloForm= function (fields) {
console.log('hello form');
};
function GroupManager(value) {
FormTools.call(this);
this.val = typeof values === 'undefined' ? 1 : value;
};
GroupManager.prototype = Object.create(FormTools.prototype);
GroupManager.prototype.constructor = GroupManager;
GroupManager.prototype.helloGroupManager= function (givenValue) {
console.log('Hello group manager');
};
Why when I try to call the group manager, it prints only the sayHelloGeneral function?
var GM = new GroupManager;
GM.sayHelloGeneral(); //->ok
GM.helloGroupManager(); //--> ok
GM.sayHelloForm(); //->sayHelloForm is not a function
It seems to be working fine. See the snippet below
var Utils = function () {};
Utils.prototype = {
sayHelloGeneral: function(){
console.log('hello');
}
};
var FormTools = function () {
Utils.call(this);
this.fields = [];
};
FormTools.prototype = Object.create(Utils.prototype);
FormTools.prototype.constructor = FormTools;
FormTools.prototype.sayHelloForm= function (fields) {
console.log('hello form');
};
function GroupManager(value) {
FormTools.call(this);
this.val = typeof values === 'undefined' ? 1 : value;
};
GroupManager.prototype = Object.create(FormTools.prototype);
GroupManager.prototype.constructor = GroupManager;
GroupManager.prototype.helloGroupManager= function (givenValue) {
console.log('Hello group manager');
};
var GM = new GroupManager;
//GM.sayhello(); //->ok---> should be sayHelloGeneral()
GM.sayHelloGeneral();
GM.helloGroupManager(); //--> ok
GM.sayHelloForm(); //->Works fine too

A Javascript function which creates an object which calls the function itself

I am trying to make an angular service that returns a new object.
That's fine and good and works. new MakeRoll() creates an instance. But self.add, near the end also calls new MakeRoll() and that doesn't create an instance when I call add like I think it should.
I'm probably doing this all wrong but I haven't been able to figure it out.
var services = angular.module('services', []);
services.factory('Roll', [function() {
var MakeRoll = function () {
var self = {};
self.rolls = [];
self.add = function(number, sizeOfDice, add) {
var newRoll = {};
newRoll.number = number || 1;
newRoll.sizeOfDice = sizeOfDice || 6;
newRoll.add = add || 0;
newRoll.rollDice = function() {
var result = 0;
var results=[];
for (var i = 0; i < newRoll.number; i++) {
var roll = Math.floor(Math.random() * newRoll.sizeOfDice) + 1;
result += roll;
results.push(roll);
}
newRoll.results = results;
newRoll.result = result;
newRoll.Roll = new MakeRoll();
};
self.rolls.push(newRoll);
return self;
};
self.remove = function(index) {
self.rolls.splice(index, 1);
};
self.get = function(index) {
return self.rolls[index];
};
return self;
};
return new MakeRoll();
}
]);
angular service is designed to be singleton to accomplish some business logic, so don't mix up plain model with angular service. if you want to have more objects, just create a constructor and link it in service to be operated on.
function MakeRoll() {
...
}
angular.module('service', []).factory('Roll', function () {
var rolls = [];
return {
add: add,
remove: remove,
get: get
}
function add() {
// var o = new MakrRoll();
// rolls.push(o);
}
function remove(o) {
// remove o from rolls
}
function get(o) {
// get o from rolls
}
});

How to "new" a returned function in Javascript

I am trying to simulate a namespace feature in Javascript.
var com = {};
com.domain = {};
com.domain.system = {};
com.domain.net = {};
com.domain.net.ip = {};
com.domain.net.ip.tcp = {};
com.domain.net.ip.udp = {};
com.domain.net.ip.ssl = {};
com.domain.util = {};
com.domain.util.timer = {};
com.domain.plugins = {};
com.domain.session = {};
com.domain.io = {};
com.domain.algorithm = {};
com.domain.debug = {};
This is the namespaces declaration. Later I will add functions to these namespaces.
This is my selector function:
For a convenient way to use namespaces, I add a function named $. This function will walk all namespaces in com. If the selected name exists, return the object.
function $ (selector) {
function digger (namespace, selector) {
for (var prop in namespace) {
if (typeof namespace[prop] == "array" || typeof namespace[prop] == "object") {
if (prop == selector) {
return namespace[prop];
}
var dig = digger(namespace[prop], selector);
if (dig != null) {
return dig;
}
} else {
if (prop == selector) {
return namespace[prop];
}
}
}
}
return digger (com, selector);
}
After that, I add a timer to namespace com.doamin.util.
com.domain.util.timer = function () {
this._handle = new InnerObj.SystemTimer(io);
return this;
};
com.domain.util.timer.prototype.expiresFromNow = function (seconds, cbHandler) {
this._handle.ExpiresFromNow (seconds, cbHandler);
};
com.domain.util.timer.prototype.wait = function (seconds, cbHandler) {
this._handle.Wait (seconds, cbHandler);
};
com.domain.util.timer.prototype.expiresAt = function (seconds, cbHandler) {
this._handle.Wait (seconds, cbHandler);
};
com.domain.util.timer.prototype.cancel = function () {
this._handle.Cancel ();
};
Usage:
1. var timer = new com.domain.util.timer (); OK
timer.expiresAt (1, {}); OK
2. var func = $("timer"); OK
var timer = new func (); OK
timer.expiresAt (1, {}); OK
But but but but but
var timer = new $("timer") (); NG
Can anyone tell me why the last new function is not working?
Try var timer = new ($("timer"))();.
Your question is not clear but I guess since $("timer") returns a function, you want a new instance of the result of $("timer") and not a new instance of $().

Javascript and module pattern

i think i did not understand javascript module pattern.
I just create this module:
var mycompany = {};
mycompany.mymodule = (function() {
var my = {};
var count = 0;
my.init = function(value) {
_setCount(value);
}
// private functions
var _setCount = function(newValue) {
count = newValue;
}
var _getCount = function() {
return count;
}
my.incrementCount = function() {
_setCount(_getCount() + 1);
}
my.degreeseCount = function() {
_setCount(_getCount() - 1);
}
my.status = function() {
return count;
}
return my;
})();
var a = mycompany.mymodule;
var b = mycompany.mymodule;
console.debug(a, 'A at beginning');
console.debug(a, 'B at beginning');
a.init(5);
b.init(2);
console.log('A: ' + a.status()); // return 2 (wtf!)
console.log('B: ' + b.status()); // return 2`
Where is the mistake?
I thought that my code would have returned to me not 2 value, but 5.
What's the reason?
a and b are the exact same objects.
var a = mycompany.mymodule;
var b = mycompany.mymodule;
What you want to do is create two different objects which have the same prototype. Something similar to this:
mycompany.mymodule = (function () {
var my = function () {};
my.prototype.init = function (value) {
_setCount(value);
};
my.prototype.incrementCount = ...
// ...
return my;
}());
a = new mycompany.mymodule();
b = new mycompany.mymodule();
a.init(5);
b.init(2);
For more info, research "javascript prototypal inheritance"
In JavaScript, objects are passed by reference, not copied.
To explain further, here is a simplified version of your code:
var pkg = (function () {
var x = {};
return x;
}());
var a = pkg;
var b = pkg;
You do not create two separate objects but only reference the object pointed at by pkg from both a and b. a and b are exactly the same.
a === b // true
This means that calling a method on a you are ultimately doing the same to b (it points to the same object—x.)
You don't want to use the module pattern for this. You want the usual constructor+prototype.
function Pkg() {
this.count = 0;
};
Pkg.prototype.init = function (count) { this.count = count; };
var a = new Pkg();
var b = new Pkg();
a === b // false
a.init(2);
a.count === 2 // true
b.count === 2 // false
Here is a good read about module pattern.

Categories

Resources