Javascript sub methods / namespacing with constructor functions - javascript

I cannot thank you enough for your time and help! I've searched for almost 2 days and cannot find my exact answer. To begin:
I've always used object literal notation to create my objects. However, I've recently come across a situation where I need to create multiple instances of the same object. I believe what I'm attempting to create are "constructor functions":
I need to have the ability to create multiple "Window" objects:
var window1 = new Window();
var window2 = new Window();
var window3 = new Window();
I want the ability to be able to organize methods as such:
window1.errorMessage.show();
window2.errorMessage.hide();
window3.errorMessage.hide();
Instead of something like:
window1.showErrorMessage();
window2.hideErrorMessage();
window3.hideErrorMessage();
An example of how I would build my window object in literal notation:
var Window = {
id: null,
init : function(id) {
this.id = id;
},
errorMessage : {
show : function(message) {
// jquery that will simply take the id of this window,
// find the errorMessage html element within the window,
// insert the "message" and show it.
},
hide : function() {
// jquery that will simply take the id of this window,
// find the errorMessage html element within this window and hide it.
}
}
}
An example of how I would attempt to build my window object using constructor functions and prototyping:
function Window(id) {
this.id = id;
this.errorMessage = function() {}
}
Window.prototype.errorMessage = function() {}
Window.errorMessage.prototype.show = function(message) {
// jquery that will simply take the id of this window,
// find the errorMessage html element within the window,
// insert the "message" and show it.
}
Window.errorMessage.prototype.hide = function() {
// jquery that will simply take the id of this window,
// find the errorMessage html element within this window and hide it.
}
When I attempt to execute the following code:
var window1 = new Window();
window1.errorMessage.show('An error message');
(Ultimately I would like to call it using:)
this.errorMessage.show('An error message');
I receive the following console errors from Firefox:
TypeError: Window.errorMessage is undefined
TypeError: Window.errorMessage.show is not a function
Thank so much for you help. I appreciate it.

I would still declare your methods on the function's prototype like you attempted, but you'll have to declare show and hide methods on a new ErrorMessage type. I think something like this is the best and most efficient (because instances of ErrorMessage will all share the same show and hide methods) thing to do (if I understand your needs correctly).
function Window(id) {
this.id = id;
this.errorMessage = new ErrorMessage();
}
function ErrorMessage() { }
ErrorMessage.prototype.show = function() {}
ErrorMessage.prototype.hide = function() {}

You only need to use prototype if you're doing inheritance. Since you're not doing inheritance forget about prototype for now.
Each Window has an instance of ErrorMessage. So I would write it like:
function Window(id) {
this.id = id;
this.errorMessage = new ErrorMessage();
}
function ErrorMessage() {
this.show = function () {};
this.hide = function () {};
}
var window1 = new Window();
window1.errorMessage.show();

Related

Prototype function overriden by other "class"

I have the following inputModel:
var UserCreateInputModel = function(req) {
...
this.password = req.body.password;
this.repeatPassword = req.body.repeatPassword;
...
console.log(this.password !== this.repeatPassword);
this.validate();
};
UserCreateInputModel.prototype = InputModel;
UserCreateInputModel.prototype.validate = function() {
console.log('Validating...');
if(this.password !== this.repeatPassword) throw new Error('Passwords are not equal!');
};
module.exports = UserCreateInputModel;
In my test I would like to test if the exception was thrown (using node's assert module):
//Act
assert.throws(function() {
new UserCreateInputModel(req);
}, Error);
Somehow the exception is just not thrown. My console output from the constructor is "this".
On the console I don't see the output "Validating".
I guess this is some JavaScript pitfall or something like that (about this) but I'm just not getting the error ...
Update
I have another inputModel in another file. This "inherites" from InputModel too. So it seems UserCreateInputModel.prototype.validate is overridden in the other inputModel. Still don't get it ...
This line:
UserCreateInputModel.prototype.validate = function() {
console.log('Validating...');
if(this.password !== this.repeatPassword) throw new Error('Passwords are not equal!');
};
is modifying the InputModel object. If you have two different types "inheriting" from InputModel with what you have here, and they both have validate methods, then one is overwriting the other.
To properly inherit from InputModel, use Object.create():
UserCreateInputModel.prototype = Object.create(InputModel.prototype);
And then call the parent constructor from your child constructor:
var UserCreateInputModel = function(req) {
InputModel.call(this, <arguments>);
This way, when you modify UserCreateInputModel.prototype, you will only be modifying UserCreateInputModel.prototype and not anything else.
UserCreateInputModel.prototype = InputModel is not how you do inheritance. Who taught you this???!!!
It's:
after the constructor, util.inherits(UserCreateInputModel, InputModel) (where util is require('util')), and
inside the constructor, calling InputModel.apply(this, arguments); or InputModel.call(this, <explicit list of input model ctr args>).
Get back with another EDIT if it still persists.

JS and methods in class emulation

I am new to this so I'll try to be as detailed as possible.
I am creating a JS class using functions.
function Bandstar(p, id)
{
var numberOfSides, Xcenter, Ycenter;
var canvas;
var circlesInt;
var linesInt;
var lines;
var linesInt2;
var linesMidToEdge;
.....
When it comes to methods, I just declare them like this:
this.IAset = function(a)
{
for (var i =0; i<= this.numberOfSides-1;i++)
{
if (parseInt(a[i]) == a[i])
this.circles[i].value = a[i];
else
return false;
}
this.IArepaint();
return true
}
and that's pretty much it.
The problem now is that, when I am creating a specific method:
this.moveFunc = function(e)
{
var p = e.target;
this.IAmove(p);
};
with the method IAmove being declared as follows:
this.IAmove = function(p)
{
var m = (p.oTop - this.Ycenter ) / (p.oLeft - this.Xcenter);
var linea = m * ( p.left - p.oLeft) + p.oTop;
var ejeX = p.left;
...
}
The compiler just keeps throwing this error:
Uncaught TypeError: Object function (e) { var p = e.target; this.IAmove(p); } has no method 'IAmove'
So, the thing is that I am declaring moveFunc as a function but then when I try to get to use this property, it doesn't actually use the instance of the class above it, (Bandstar), but of itself (and obviously moveFunc doesn't have a method called IAmove, the class on which it is being created is)...
I thought this was just like it worked, but I must not be getting the concept of heritage and class morphology in JS right.
How can I access a method in a class from another method inside that same class? If I just write IAmove(p) it will just say the method IAmove() is undefined (because it isn't, it's part of the Bandstar namespace.
I know it must be something stupid that I'm not seeing. Any suggestions?
The context inside your function may change based on your call. So this could not be the original object.
You should add a private var like:
function Bandstar(p, id)
{
var numberOfSides, Xcenter, Ycenter;
var canvas;
var that = this; // add this line
and use it when you try to call function (or get properties) of original object
this.moveFunc = function(e)
{
var p = e.target;
that.IAmove(p); // change this line
};
for be sure to point to original object.
EDIT: According with comments you can read more infos in Stuart's answer
You probably wants to add these methods to your Bandstar prototype.
function Bandstar(p, id)
{
// ...
}
Bandstar.prototype.IAset = function(a)
{
// ...
}
Bandstar.prototype.moveFunc = function(e)
{
var p = e.target;
this.IAmove(p);
};
This way your methods keep the Bandstar context, and this will remain Bandstar instance reference.
Have a look at Object.prototype reference
Assuming all of those methods are defined in the constructor the syntax is correct. The following fiddle illustrates it working, the code is based on a simplified version of your code...
function Test() {
this.move = function(p) {
document.write("Moved to: " + p);
};
this.another = function(e) {
this.move(e.target);
};
}
var test = new Test();
test.another({target: "The moon"});
The cause of the issues is likely to be one of two three things:
How the method moveFunc is called
When the method moveFunc is called
How the method IAmove is called (it may not be the moveFunc function that is causing that error).
The this keyword will reference the scope of the function which is typically the owner of the method...
var bandstar = new Bandstar(p, id);
bandstar.moveFunc(e); // this should be bandstar
The only reasons that might not be the case is if you are explicitly binding the moveFunc function to another object or a more common situation is that the function is being called without being attached to the owner...
var bandstar = new Bandstar(p, id);
var moveFunc = bandstar.moveFunc(e);
moveFunc(e); // this will now be window
The this keyword will default to window if the owner is detached from it. You can bind the function using.
var bandstar = new Bandstar(p, id);
var moveFunc = bandstar.moveFunc(e);
moveFunc.bind(bandstar);
moveFunc(e); // this will now be bandstar again
In the second issue both methods must be defined in the constructor before the moveFunc function can be called
this.moveFunc = function(e) { ... }
this.moveFunc(e); // Will throw an error that IAmove does not exist in the object
this.IAmove = function(p) { ... }
You can log the this object using console.log(this); to find out what it is.
It looks as though from your error that you are trying to call IAmove on the moveFunc function. For this error to be caused you would need to have called moveFunc with itself as the owner or the bound object... Which is not a particularly likely.
I have a hunch that the error may not actually be related to the this.IAmove(p); call in the moveFunc as assumed. Post the stack trace and we can use that to find where the error occurred.

How can instantiated JavaScript objects communicate with each other?

I think the best way to ask my question is by giving an example.
In JavaScript, imagine the following scenario:
function Tab(options) {
this.options = options;
}
Tab.prototype.doSomething = function () {
if(...) {
// Change tab1's options
//tab1.disabled = true
} else {
// Change tab2's options
//tab2.disabled = true
}
// Call a method on of mySlider instance (NOT myOtherSlider instance)
//mySlider.helloWorld();
}
// Slider class
function Slider(options) {
....
}
Slider.prototype.helloWorld = function () {
...
// Access tab1's properties
// tab1.disabled should be "TRUE" since it was changed previously
// Access tab2's properties
...
}
function Accordion() {
this.name = 'accordion';
var tab1 = new Tab({disabled: true}),
tab2 = new Tab({disabled: false),
mySlider = new Slider({color: red}),
myOtherSlider = new Slider({color: blue});
}
Pretty much I would like all the classes to be aware of the objects that has been instantiated in their own class as well as other classes.
The important part is for the instances to be synchronized. For example, a change to tab1's properties should be applied/visible to any other objects accessing tab1.
I managed to answer my own question by using an object manager class:
function ObjectManager () {
}
ObjectManager.objects = {};
ObjectManager.register = function (name, object) {
var t = this;
t.objects[name] = object;
}
ObjectManager.getObject = function (name) {
var t = this;
return t.objects[name];
}
function Tab () {
this.name = 'tab object';
}
Tab.prototype.init = function (name) {
var t = this;
t.name = name;
}
Tab.prototype.changeProperty = function () {
var tab1 = ObjectManager.getObject('tab1');
tab1.name = 'changed tab1 name';
}
function Accordion() {
var tab1 = new Tab();
tab1.init('tab number 1');
var tab2 = new Tab();
tab2.init('tab number 2');
ObjectManager.register('tab1', tab1);
ObjectManager.register('tab2', tab2);
console.log(ObjectManager.objects);
tab2.changeProperty();
console.log(ObjectManager.objects);
console.log(tab1.name);
}
var accordion = new Accordion();​
Though I am not sure how efficient this solution is, but it gets the job done.
There are many different approaches to this problem. Let me explain two common patterns:
The observer pattern. Each object which needs to be informed about changes in other objects ("observer"), is passed to the "register" method of the objects it needs to be informed about ("observed"). The observed object keeps an internal array of all observers which registered for it. The observed also registers handlers for all relevant input events on the DOM element it represents (onclick, onchange etc). When the observed is changed, it informs all observers by calling a common method in them.
The controller pattern. All objects are managed by a central controller object. The controller keeps arrays of all objects which need to be managed. All input events are handled by the controller. When an input event occurs, it determines which objects need to be changed because of this event and changes them.

Understanding Classes and Inheritance in Javascript - New Pattern

I'm designing an OOP inheritance pattern for many applications I'm building. Javascript has many ways of doing this, but I stumbled on a pattern I really like. But now I'm struggling with the need for a separation of classes and instances.
I have a base object called Root. And it has a main method called inherit. To create a new object you use
var Person = Root.inherit({
name : "",
height : 0,
walk : function() {},
talk : function() {}
});
Then to create an "instance" you would
var sally = Person.inherit({
name : "sally",
height : "5'6"
});
sally can .talk() and she can walk() and she has a .name and a .height
You can make more people the same way.
If you want a constructor you use
var Person = Root.inherit({
_construct : function() {
// do things when this object is inherited from
},
name : "",
height : 0,
walk : function() {},
talk : function() {}
});
It also has the ability to have init, when the object is first defined in code (singletons use this)
var Person = Root.inherit({
_init : function() {
// called at runtime, NOT called if an object is inherited from me
},
name : "",
height : 0,
walk : function() {},
talk : function() {}
});
So as you can see, everything uses .inhert(). There are no classes and no instances really. Everything is an instance of something. The only real problem I found so far is that there is no concept of "type", but you can always just check for a method if you need to. Also you can't protect a 'class', as a 'class' can be changed during execution if the developer accidentally changed it, or meant to change it.
So my question is: Is there a need in javascript to have an explicitly and controlled separation of class structure and instances of the class? Are there any issues with treating every object as an instance?
No there's no need since Javascript is a Prototypal based language, meaning that classes are not involved. You are just creating clones of the objects.
http://en.wikipedia.org/wiki/Prototype-based_programming
As far as the concept of type, the type is object.
A good read for more info about this would be Javascript Patterns by Stoyan Stefanov he has several different creational patterns that address your concerns, including examples that implement Design Patterns from the gang of four's design patterns.
http://www.amazon.com/JavaScript-Patterns-Stoyan-Stefanov/dp/0596806752
So my question is: Is there a need in javascript to have an explicitly and controlled separation of class structure and instances of the class? Are there any issues with treating every object as an instance?
Not really, if you're happy with it, it's fine.
The more normal form of JavaScript inheritance does much the same thing. You'll frequently see structures like this (severely cut down for brevity):
function Base() {
}
Base.prototype.foo = function() {
};
function Derived() {
}
Derived.prototype = new Base();
...and of course, new Base() is also how you create instances of Base. So your system is quite similar.
Again, the above is a sketch, not a full example. For one thing, usually you'd see construction and initialization separated out, so you don't literally see Derived.prototype = new Base() so much as something that creates an object with Base's prototype but without actually calling Base (which Derived would do later), but you get the idea. Granted that statement somewhat weakens the similarity with your system, but I don't think it breaks it at all.
At the end of the day, it's all about objects (instances), which are either used directly (your sally) or indirectly by providing features to other objects (Person, Root) by cloning or by setting them up as the prototype of the other object.
Javascript's inheritance is prototypical which means everything object is an instance. You actually have to do extra work to get the classical inheritance.
This is how I work in javascript
// this is class
function person(){
// data is member variable
this.name = null;
this.id = null;
//member functions
this.set_name = _set_name;
this.get_name = _get_name;
this.set_id = _set_id;
this.get_id = _get_id;
function _set_name(name){
this.name = name;
}
function _get_name(name){
return this.name;
}
function _set_id(id){
this.id = id;
}
function _get_id(id){
return this.id;
}
}
// this is instance
var yogs = new person();
yogs.set_id(13);
yogs.set_name("yogs");
hope it may help
Start with some basic object...
// javascript prototypes - callback example - javascript objects
function myDummyObject () {
that = this;
} // end function myDummyObject ()
// begin dummy object's prototype
myDummyObject.prototype = {
that : this,
// add a simple command to our dummy object and load it with a callback entry
say : function () {
var that = this;
console.log('speaking:');
that.cb.run("doSay");
}
} // end myDummyObject proto
extend with a sub prototype..
// here we addon the callback handler... universally self sufficient object
var cb = {
that : this, // come to papa ( a link to parent object [ myDummyObject ] )
jCallback : new Array(new Array()), // initialize a javascript 2d array
jCallbackID : -1, // stores the last callback id
add: function(targetFnc, newFunc) {
var that = this;
var whichID = that.jCallbackID++;
// target, addon, active
that.jCallback[that.jCallback.length] = { 'targetFunc' : targetFnc, 'newFunc' : newFunc, 'active' : true, 'id': whichID };
return whichID; // if we want to delete this later...
}, // end add
run: function(targetFnc) {
var that = this;
for(i=0;i <= that.jCallback.length - 1;i++) // go through callback list
if( that.jCallback[i]['targetFunc'] == targetFnc && that.jCallback[i]['active'] == true )
that.jCallback[i]['newFunc'](); // run callback.
}, // end run
remove: function (whichID) {
var that = this;
console.log('removing:' + whichID);
for(i=0;i <= that.jCallback.length - 1;i++) // go through callback list
if( that.jCallback[i]['id'] == whichID )
that.jCallback[i]['newFunc'](); // run callback.
} // end remove
}
// add the object to the dummy object...
myDummyObject.prototype.cb = cb;
Example:
var testing = new myDummyObject();
testing.cb.add('doSay', function () { console.log('test: 213123123'); } );
// test remove...
var testid = testing.cb.add('doSay', function () { console.log('test: 12sad31'); } );
testing.cb.remove(testid);
testing.cb.add('doSay', function () { console.log('test: asdascccc'); } );
testing.cb.add('doSay', function () { console.log('test: qweqwe'); } );
testing.cb.add('doSay', function () { console.log('test: d121d21'); } );
testing.cb.add('doSay', function () { console.log('test: wwww'); } );
testing.say();
This always seemed the easiest for me to understand... Just create a new instance of the inherited class and then loop through its variables and methods and add them to the main one.
var myPerson = new Person()
var myPerson.firstName = 'john';
var myPerson.lastName = 'smith';
var myPerson.jobTitle = 'Programmer';
var Person = function(){
//Use this to inherit classes
this._extendedClass = new Person_Job();
for(var i in this._extendedClass){
this[i] = this._extendedClass[i];
}
delete this._extendedClass;
this.firstName = '';
this.lastName = '';
}
var Person_Job = function() {
this.jobTitle = '';
}

JavaScript nested object reference to parent

I'm working on a fairly complex object in JS and I'm running into issues:
I have the following (abridged) code:
var LocationSelector;
LocationSelector = function(container) {
this.selectors = {
container: container,
city_name: container.find('input.city_name'),
city_id: container.find('input.city_id')
};
return this.initialize();
};
LocationSelector.prototype = {
initialize: function() {
return this.city.checkStatus();
},
city: {
status: null,
message: null,
id: null,
checkStatus: function() {
if (LocationSelector.selectors.city_name.val() && LocationSelector.selectors.city_id.val()) {
return LocationSelector.city.setStatus('success');
}
},
setStatus: function(status) {
return alert(status);
}
}
};
Two questions:
1) Inside of a sub-object function this no longer refers back to the root object. It seems I can refer back to the parent if I write out LocationSelector.object.method( args ), but that's a lot to type. Is there a way to define a shortcut back to the parent object?
2) In some situations I need to have several instances of this per page, so it's important to me that I can set the various selectors when a new object is instantiated and then refer to the instance selectors in the prototype. Is referring to the parent object (ie. LocationSelector) in sub-object methods even viable for that? How does JS know to stay with the currently active object's stored properties?
Basically, I'm trying to implement a class, and I'm totally new to JS and don't really know how to do it. So, any help or suggestions are appreciated. Thanks!
There are many things wrong with your current approach. Here is something closer to what you want, although I do not understand why LocationSelector instances have a city member.
function LocationSelector(container) {
this.selectors = {
container: container,
city_name: container.find("input.city_name"),
city_id: container.find("input.city_id")
};
this.city = new City(this);
this.city.checkStatus();
}
function City(locationSelector) {
this.status = null;
this.message = null;
this.id = null;
this.locationSelector = locationSelector;
}
City.prototype.checkStatus = function () {
if (this.locationSelector.selectors.city_name.val() && this.locationSelector.selectors.city_id.val()) {
this.setStatus("success");
}
};
City.prototype.setStatus = function () {
alert("status");
};
Things to note:
Data properties go on the instance, not the prototype. Only methods go on the prototype.
City is clearly its own class, so you should make it one. In your code, a single city is being shared between all instances of LocationSelector, since it is put on the prototype. In this code, it is assigned as an instance property, in the LocationSelector constructor.
You cannot reference LocationSelector.selectors like you do in your example. LocationSelector.selectors would be for "static" properties, which LocationSelector does not have. Instead you need to refer to the selectors property on specific instances; in this example, that instance is given by this.locationSelector.
Points 2 and 3 speak to an important fact: the "child" City instance cannot reference to properties of the "parent" LocationSelector class without having a concrete instance of it.
Here is a version of the code that makes more sense to me, removing the part where LocationSelector has a city property (which it doesn't use).
function LocationSelectors(container) {
this.city_name = container.find("input.city_name");
this.city_id = container.find("input.city_id");
}
function City(locationSelectors) {
this.locationSelector = locationSelector;
}
City.prototype.checkStatus = function () {
if (this.locationSelectors.city_name.val() && this.locationSelectors.city_id.val()) {
this.setStatus("success");
}
};
City.prototype.setStatus = function () {
alert("status");
};
function checkCityStatus(container) {
var locationSelectors = new LocationSelectors(container);
var city = new City(locationSelectors);
city.checkStatus();
}
I leave you with a link to Crockford's "Private Members in JavaScript", which talks about doing OO in JavaScript. There are other, probably better explanations out there, but at least that one will put you on the right track.
Read about Closures and I'm positive you will find what you need.
Here's is a quick example of what you are trying to accomplish:
function MyCoolObject(name){
var self_myCoolObject = this;
this.name = name;
this.popAlertWithNameInFiveSeconds = function(){
setTimeout(function(){
alert('Incorrect reference to name "this.name" returns ' + this.name);
alert('Correct reference to name "self_myCoolObject.name" returns ' + self_myCoolObject.name);
},5000)
}
}
//TO TEST
var MyObj = new MyCoolObject('MySuperCoolName')
MyObj.popAlertWithNameInFiveSeconds();
Here is a snippet of JS code that I have. Before I drop down into a click handler, I make a reference to the object (SlideShow) by calling var parent = this. Then in later nested functions, you can be sure you're calling the right scope by using parent.function()
/* Slide Show object */
function SlideShow(parentContainerId) {
this.BEGINNING = 'Beginning';
this.END = 'End of list';
this.FIRSTINDEX = 0;
this.length = jQuery(parentContainerId + ' img').length;
this.container = jQuery(parentContainerId);
this.imgs = jQuery(parentContainerId + ' img');
this.index = this.FIRSTINDEX;
this.status = 'beginning'; // beginning, end
this.init = function() {
// get it started
this.moveTo(this.FIRSTINDEX);
this.process();
// ****GET OBJECT SCOPE*****
var parent = this;
// set up click listener
this.container.find('img').click(function(e) {
var item_width = jQuery(this).width();
var x_click_ps = e.clientX - jQuery(this).offset().left;
var x_diff = x_click_ps / item_width;
console.log(this);
if (x_diff < .5) {
parent.moveByIncrement(-1)
parent.process();
} else {
parent.moveByIncrement(1);
parent.process();
}
});
}
.
.
.
}

Categories

Resources