How to create an Custom Object with a Custom Object? - javascript

In Javascript how would I create a Custom Object that has a property this is another Custom Object.
For Example.
function Product() {
this.prop1 = 1;
this.prop2 = 2;
}
function Work(values) {
this.front = values.front || "default";
this.back = values.back || "default";
this.product = Product;
}
var w = new Work();
alert(w.product.prop1); //no worky

You need to create an instance of Product, like this:
function Product() {
this.prop1 = 1;
this.prop2 = 2;
}
function Work(values) {
this.front = values && values.front || "default";
this.back = values && values.back || "default";
this.product = new Product();
}
var w = new Work();
alert(w.product.prop1); //1
The front and back changes are a separate issue, since values wasn't being passed in in your example, you'd get an undefined error. You can test the result here.
Here's an alternative way I'd personally use to define those defaults:
function Work(values) {
values = values || { front: "default", back: "default" };
this.front = values.front;
this.back = values.back;
this.product = new Product();
}
You can try that version here.

Related

What is wrong with my observable pattern?

I'm testing the observable pattern in javascript. My callbacks in the array never seem to execute. What is wrong with my syntax?
<script type="text/javascript">
var Book = function (value) {
var onChanging = [];
this.name = function () {
for (var i = 0; i < onChanging.length; i++) {
onChanging[i]();
}
return value;
}
this.addTest = function (fn) {
onChanging.push(fn);
}
}
var b = new Book(13);
b.addTest(function () { console.log("executing"); return true; });
b.name = 15;
</script>
From your code above it looks like you need to call your function name instead of assigning a value something like:
var b = new Book(13);
b.addTest(function () { console.log("executing"); return true; });
b.name(); //<-- Before b.name = 15
Setting b.name = 15 doesn't execute the function, it just overwrites the value of b.name.
You could use getters and setters to react to a changing value. See John Resig's blog post or the MDN reference
I edited your code to use them:
var Book = function (value) {
this.onChanging = [];
this._name = "";
}
Book.prototype = {
addTest: function (fn) {
this.onChanging.push(fn);
},
get name() {
return this._name;
},
set name(val) {
for (var i = 0; i < this.onChanging.length; i++) {
this.onChanging[i](val);
}
this._name = val;
}
};
var b = new Book(13);
b.addTest(function (val) {
console.log("executing", val);
return true;
});
b.name = 15;
b.name = 17;
working demo.
You can also make a more generic solution that can work for all your properties without having to define the getters and setters, a lot of frameworks use this approach.
Book = function () {
this._events = [];
this._rawdata = {};
}
Book.prototype = {
bind: function (fn) {
this._events.push(fn);
},
// pass the property, and it returns its value, pass the value and it sets it!
attr: function (property, val) {
if (typeof val === "undefined") return this._rawdata[property];
this._rawdata[property] = val;
for (var i = 0; i < this._events.length; i++)
// we pass out the val and the property
this._events[i](val, property);
}
};
b = new Book();
b.bind(function (val) {
console.log("executing", val);
return true;
});
b.attr("name","The Hobbit");
b.attr("SKU" ,1700109393901);
console.log(b.attr("name")); // --> The Hobbit
http://jsfiddle.net/wv4ch6as/
Of course you would want to change the binder so that you can bind onto properties not one bind for all properties, but I think this gets the idea.

How to write a object oriented Node.js model

I am having a lot of trouble writing an object oriented Cat class in Node.js. How can I write a Cat.js class and use it in the following way:
// following 10 lines of code is in another file "app.js" that is outside
// the folder "model"
var Cat = require('./model/Cat.js');
var cat1 = new Cat(12, 'Tom');
cat1.setAge(100);
console.log(cat1.getAge()); // prints out 100 to console
var cat2 = new Cat(100, 'Jerry');
console.log(cat1.equals(cat2)); // prints out false
var sameAsCat1 = new Cat(100, 'Tom');
console.log(cat1.equals(sameAsCat1)); // prints out True
How would you fix the following Cat.js class I have written:
var Cat = function() {
this.fields = {
age: null,
name: null
};
this.fill = function (newFields) {
for(var field in this.fields) {
if(this.fields[field] !== 'undefined') {
this.fields[field] = newFields[field];
}
}
};
this.getAge = function() {
return this.fields['age'];
};
this.getName = function() {
return this.fields['name'];
};
this.setAge = function(newAge) {
this.fields['age'] = newAge;
};
this.equals = function(otherCat) {
if (this.fields['age'] === otherCat.getAge() &&
this.fields['name'] === otherCat.getName()) {
return true;
} else {
return false;
}
};
};
module.exports = function(newFields) {
var instance = new Cat();
instance.fill(newFields);
return instance;
};
If I were to design an object like this, then I would have done like this
function Cat(age, name) { // Accept name and age in the constructor
this.name = name || null;
this.age = age || null;
}
Cat.prototype.getAge = function() {
return this.age;
}
Cat.prototype.setAge = function(age) {
this.age = age;
}
Cat.prototype.getName = function() {
return this.name;
}
Cat.prototype.setName = function(name) {
this.name = name;
}
Cat.prototype.equals = function(otherCat) {
return otherCat.getName() == this.getName()
&& otherCat.getAge() == this.getAge();
}
Cat.prototype.fill = function(newFields) {
for (var field in newFields) {
if (this.hasOwnProperty(field) && newFields.hasOwnProperty(field)) {
if (this[field] !== 'undefined') {
this[field] = newFields[field];
}
}
}
};
module.exports = Cat; // Export the Cat function as it is
And then it can be used like this
var Cat = require("./Cat.js");
var cat1 = new Cat(12, 'Tom');
cat1.setAge(100);
console.log(cat1.getAge()); // 100
var cat2 = new Cat(100, 'Jerry');
console.log(cat1.equals(cat2)); // false
var sameAsCat1 = new Cat(100, 'Tom');
console.log(cat1.equals(sameAsCat1)); // true
var sameAsCat2 = new Cat();
console.log(cat2.equals(sameAsCat2)); // false
sameAsCat2.fill({name: "Jerry", age: 100});
console.log(cat2.equals(sameAsCat2)); // true
I would use a class :
class Cat {
fields = {
age: null,
name: null
};
fill(newFields) {
for(var field in this.fields) {
if(this.fields[field] !== 'undefined') {
this.fields[field] = newFields[field];
}
}
}
getAge() {
return this.fields.age;
}
setAge(newAge) {
this.fields.age = newAge;
}
}
exports.Cat = Cat;
This code is working fine Person.js code here
exports.person=function(age,name)
{
age=age;
name=name;
this.setAge=function(agedata)
{
age=agedata;
}
this.getAge=function()
{
return age;
}
this.setName=function(name)
{
name=name;
}
this.getName=function()
{
return name;
}
};
call object code:
var test=require('./route/person.js');
var person=test.person;
var data=new person(12,'murugan');
data.setAge(13);
console.log(data.getAge());
data.setName('murugan');
console.log(data.getName());
There is error loop hole in answers by #thefourtheye, I will describe those below
Object modelling rules
Create empty new object
Create Filled Object
Only Initial object should be set by machine/code
After Initial object assignment Any changes in your object should happen by user interaction only.
After Initial object assignment Any changes in object by code without user intention is going to add some bugs
Problem Use case :
Eg - So when you create filled object , at that time if any property(somedate) is not having any value then due to below code the default value gets assigned to it(somedate) , which is against object modelling rules.
Bug
Constructor function is given Dual responsibility to create new
& filled object which he mixes up while creating filled object , And
its going to make mistakes.
Means there is some buggy code in your app that is going to set values by it self without users intention
function Cat(age, name, somedate ) { // Accept name and age in the constructor this.name = name || null; this.age = age || null; this.somedate = somedate || new Date(); //there will be lots of usecases like this }
So to solve this Problem i use below JavaScript data model.
So it allows user to create filled object Or new object intentionally only when need any one of them and not messing with each other
class Cat {
constructor(){
this.name = null;
this.age = null;
}
initModel (data) {
this.name = data.name;
this.age = data.age
}
getAge () { return this.age;}
setAge (age) { this.age = age; }
getName () {this.name;}
setName (name) {this.name = name;}
equals (otherCat) {
return otherCat.getName() == this.getName()
&& otherCat.getAge() == this.getAge();
}
fill (newFields) {
for (let field in newFields) {
if (this.hasOwnProperty(field) && newFields.hasOwnProperty(field)) {
if (this[field] !== 'undefined') {
this[field] = newFields[field];
}
}
}
};
}
let cat1 = new Cat();
cat1.initModel({age : 12,name :'Tom'})
cat1.setAge(100);
console.log(cat1.getAge()); // 100
let cat2 = new Cat();
cat2.initModel({age : 100,name : 'Jerry'})
console.log(cat1.equals(cat2)); // false
let sameAsCat1 = new Cat({age : 100,name : 'Tom'});
sameAsCat1.initModel({age : 100,name : 'Tom'})
console.log(cat1.equals(sameAsCat1)); // true
let sameAsCat2 = new Cat();
console.log(cat2.equals(sameAsCat2)); // false
sameAsCat2.fill({name: "Jerry", age: 100});
console.log(cat2.equals(sameAsCat2));
Note :
Constructor is only used For creating new Object
InitModel is only used For creating filled Object

Node Module Inheritance

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;

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