Encapsulating Class Definitions in JavaScript for Cleaner Namespace - javascript

I'm creating a quiz interaction, and after a few days of research I'm trying to determine the best way to declare my objects. There's a master anonymous function (which could be called Quiz, but there is no requirement for public methods) that contains a class definition for Scenarios that contain a class definition for Questions:
Quiz > Scenario > Questions > Answers (eventually)
I prefer the Immediately-Invoked ('iffy') model to enforce private/public, but I also require multiple instances, so I believe I should be using prototypes? I've placed the class definitions as private as they are only used by this interaction. Is this the best model?
JsFiddle: http://jsfiddle.net/QtCm8/
(function(quizData) {
var scenarios = [];
for(var s=0;s<quizData.scenarios.length;s++) scenarios.push(new Scenario(quizData.scenarios[s]));
function Scenario(scenarioData) {
console.log("New Scenario: " + scenarioData.title);
var questions = [];
for(var q=0;q<scenarioData.questions.length;q++) questions.push(new Question(scenarioData.questions[q]));
function Question(questionData) {
console.log("New Question: " + questionData.text);
// Repeat pattern for future answers object
}
}
})({
scenarios: [
{
title: 'Scenario1'
,questions: [
{
text: 'What is 1+1?'
}
,{
text: 'What is 2+2?'
}
]
}
]
});

Consider packing your classes into objects. The following is a design pattern that I came up with. Since you have so many classes that rely on each other I thought it better to line them up into one object. Here is the code:
var quiz = {};
quiz.init = (function(data) {
this.scenarios = this.questions = this.answers = [];
this.data = {
Question: data.Question.bind(this),
Answer: data.Answer.bind(this),
Scenario: data.Scenario.bind(this)
};
this.set_data = function(qas) {
// fill the arrays here
// Question, Scenario and Answer are now this.data.Question/Answer...
// you can use a variable to shorten the names here
};
});
var Quiz = function(data) {
return new quiz.init(data);
};
var data = { // classes are defined here
Question: function() {},
Answer: function() {},
Scenario: function() {}
};
var q = Quiz( data );
q.data.set_data(/* Big object literal goes here */);

Personally, I like to use class definitions that return the properties that they wish to make public. Below is an example for your case. You could play around with the structure and find something that you like best, but it should give you some examples:
// Namespace
var q = {};
q.Quiz = function Quiz (data) {
// Private code & variables
var scenarios = [];
for (var i = 0; i < data.scenarios.length; i++) {
scenarios.push(new q.Scenario(data.scenarios[i]));
}
// Return public methods & values
return {
scenarios: scenarios
};
};
q.Scenario = function Scenario (sData) {
// Private inner class
var Question = function (qData) {
console.log("New Question: " + qData.text);
return {
text: qData.text
};
};
console.log("New Scenario: " + sData.title);
var questions = [];
for (var i = 0; i < sData.questions.length; i++) {
questions.push(new Question(sData.questions[i]));
}
return {
questions: questions
};
};
var data = {
scenarios: [
{
title: 'Scenario1'
,questions: [
{
text: 'What is 1+1?'
}
,{
text: 'What is 2+2?'
}
]
}
]
};
console.log(new q.Quiz(data));
Working example here: http://jsfiddle.net/5M8bp/
Alternatively, you get rid of the return statement and define public properties and methods using the 'this' keyword. For example:
q.Quiz = function Quiz (data) {
this.scenarios = [];
for (var i = 0; i < data.scenarios.length; i++) {
this.scenarios.push(new q.Scenario(data.scenarios[i]));
}
};
q.Scenario = function Scenario (sData) {
// Private inner class
var Question = function (qData) {
console.log("New Question: " + qData.text);
this.text = qData.text;
};
console.log("New Scenario: " + sData.title);
this.questions = [];
for (var i = 0; i < sData.questions.length; i++) {
this.questions.push(new Question(sData.questions[i]));
}
};

First, there are no classes in Javascript, just objects. It is a prototype-based language (not class-based), and its functions are first-class objects. By the way, a prototype is an object, and every function you create gets it pointing to a new blank object. There is just a concept of "class" simulated using functions.
This immediate pattern (aka anonymous function) is very useful to provide a cleaner namespace, as you said. It also useful when there is a work that needs to be done only once, e.g. initialization code, so there is no reason to have a reusable named function.
However, if you need reusable members (e.g. a method), yes, it should go to the prototype. Adding common properties and methods to the prototype property, allows these common parts to be shared among all the instances created using the same constructor.
Maybe you are looking for the Module Pattern, which is a combination of patters like
namespace,
immediate functions,
private members etc.

Related

Making private instance variable accessible to prototype methods enclosed in anonymous function

Background
I decided I would practice by making a simple calculator app in JS. The first step was to implement a stack class. I ran into some problems however in achieving data encapsulation with the revealing prototype pattern (?). Here's how it looks right now:
Stack "class":
var Stack = (function () {
var Stack = function() {
this.arr = []; // accessible to prototype methods but also to public
};
Stack.prototype = Object.prototype; // inherits from Object
Stack.prototype.push = function(x) {
this.arr.push(x);
};
Stack.prototype.pop = function() {
return this.arr.length ? (this.arr.splice(this.arr.length - 1, 1))[0] : null;
};
Stack.prototype.size = function() {
return this.arr.length;
};
Stack.prototype.empty = function() {
return this.arr.length === 0;
};
return Stack;
})();
Test code:
var s1 = new Stack();
var s2 = new Stack();
for(var j = 1, k = 2; j < 10, k < 11; j++, k++) {
s1.push(3*j);
s2.push(4*k);
}
console.log("s1:");
while(!s1.empty()) console.log(s1.pop());
console.log("s2:");
while(!s2.empty()) console.log(s2.pop());
The Problem
The only problem is that the arr is accessible. I would like to hide the arr variable somehow.
Attempts at a Solution
My first idea was to make it a private variable like Stack:
var Stack = (function () {
var arr = []; // private, but shared by all instances
var Stack = function() { };
Stack.prototype = Object.prototype;
Stack.prototype.push = function(x) {
arr.push(x);
};
// etc.
})();
But of course this approach doesn't work, because then the arr variable is shared by every instance. So it's a good way of making a private class variable, but not a private instance variable.
The second way I thought of (which is really crazy and definitely not good for readability) is to use a random number to restrict access to the array variable, almost like a password:
var Stack = (function() {
var pass = String(Math.floor(Math.pow(10, 15 * Math.random()));
var arrKey = "arr" + pass;
var Stack = function() {
this[arrKey] = []; // private instance and accessible to prototypes, but too dirty
};
Stack.prototype = Object.prototype;
Stack.prototype.push = function(x) {
this[arrKey].push(x);
};
// etc.
})();
This solution is... amusing. But obviously not what I want to do.
The last idea, which is what Crockford does, allows me to create a private instance member, but there's no way I can tell to make this visible to the public prototype methods I'm defining.
var Stack = (function() {
var Stack = function() {
var arr = []; // private instance member but not accessible to public methods
this.push = function(x) { arr.push(x); }; // see note [1]
}
})();
[1] This is almost there, but I don't want to have the function definitions within the var Stack = function() {...} because then they get recreated every time that an instance is created. A smart JS compiler will realize that they don't depend on any conditionals and cache the function code rather than recreating this.push over and over, but I'd rather not depend on speculative caching if I can avoid it.
The Question
Is there a way to create a private instance member which is accessible to the prototype methods? By somehow utilizing the 'bubble of influence' created by the enclosing anonymous function?
You could use a factory function that creates an instance for you:
function createStack() {
var arr = [];
function Stack() {
};
Stack.prototype = Object.prototype; // inherits from Object
Stack.prototype.push = function(x) {
arr.push(x);
};
Stack.prototype.pop = function() {
return arr.length ? (this.arr.splice(this.arr.length - 1, 1))[0] : null;
};
Stack.prototype.size = function() {
return arr.length;
};
Stack.prototype.empty = function() {
return arr.length === 0;
};
return new Stack();
}
You would be defining the class on every execution of the factory function, but you could get around this by changing this to define most of Stack outside the constructor function, like the parts that dont use arr could be further up the prototype chain. Personally I use Object.create instead of prototype now and I almost always use factory functions to make instances of these types of objects.
Another thing you could do is maintain a counter that keeps track of the instance and holds on to an array of arrays.
var Stack = (function() {
var data = [];
var Stack = function() {
this.id = data.length;
data[this.id] = [];
};
Stack.prototype = Object.prototype;
Stack.prototype.push = function(x) {
data[this.id].push(x);
};
// etc.
}());
Now you have the hidden data multi dimensional array, and every instance just maintains its index in that array. You have to be careful to manage the memory now though, so that when your instance isn't being used anymore you remove what's in that array. I don't recommend doing it this way unless you are disposing your data carefully.
The short answer here, is that you can't have all things, without sacrificing a little.
A Stack feels like a struct of some kind, or at very least, a data-type which should have either a form of peek or read-access, into the array.
Whether the array is extended or not, is of course up to you and your interpretation...
...but my point is that for low-level, simple things like this, your solution is one of two things:
function Stack () {
this.arr = [];
this.push = function (item) { this.arr.push(item); }
// etc
}
or
function Stack () {
var arr = [];
var stack = this;
extend(stack, {
_add : function (item) { arr.push(item); },
_read : function (i) { return arr[i || arr.length - 1]; },
_remove : function () { return arr.pop(); },
_clear : function () { arr = []; }
});
}
extend(Stack.prototype, {
push : function (item) { this._add(item); },
pop : function () { return this._remove(); }
// ...
});
extend here is just a simple function that you can write, to copy the key->val of objects, onto the first object (basically, so I don't have to keep typing this. or Class.prototype..
There are, of course, dozens of ways of writing these, which will all achieve basically the same thing, with modified styles.
And here's the rub; unless you do use a global registry, where each instance is given its own unique Symbol (or unique-id) at construction time, which it then uses to register an array... ...which of course, means that the key then needs to be publicly accessible (or have a public accessor -- same thing), you're either writing instance-based methods, instance-based accessors with prototyped methods, or you're putting everything you need in the public scope.
In the future, you will be able to do things like this:
var Stack = (function () {
var registry = new WeakMap();
function Stack () {
var stack = this,
arr = [];
registry[stack] = arr;
}
extend(Stack.prototype, {
push (item) { registry[this].push(item); }
pop () { return registry[this].pop(); }
});
return Stack;
}());
Nearly all bleeding-edge browsers support this, currently (minus the shorthand for methods).
But there are ES6 -> ES5 compilers out there (Traceur, for instance).
I don't think WeakMaps are supported in Traceur, as an ES5 implementation would require a lot of hoops, or a working Proxy, but a Map would work (assuming that you handled GC yourself).
This lends me to say that from a pragmatic standpoint, for a class as small as Stack you might as well just give each instance its own methods, if you really want to keep the array internal.
For other harmless, tiny, low-level classes, hiding data might be pointless, so all of it could be public.
For larger classes, or high-level classes, having accessors on instances with prototyped methods stays relatively clean; especially if you're using DI to feed in lower-level functionality, and the instance accessors are just bridging from the interface of the dependency, into the shape you need them to be, for your own interface.
A real solution
EDIT: It turns out this solution is basically the same as the one described here, first posted by HMR in a comment to my question above. So definitely not new, but it works well.
var Stack = (function Stack() {
var key = {};
var Stack = function() {
var privateInstanceVars = {arr: []};
this.getPrivateInstanceVars = function(k) {
return k === key ? privateInstanceVars : undefined;
};
};
Stack.prototype.push = function(el) {
var privates = this.getPrivateInstanceVars(key);
privates.arr.push(el);
};
Stack.prototype.pop = function() {
var privates = this.getPrivateInstanceVars(key);
return privates.arr.length ? privates.arr.splice(privates.arr.length - 1, 1)[0] : null;
};
Stack.prototype.empty = function() {
var privates = this.getPrivateInstanceVars(key);
return privates.arr.length === 0;
};
Stack.prototype.size = function() {
var privates = this.getPrivateInstanceVars(key);
return privates.arr.length;
};
Stack.prototype.toString = function() {
var privates = this.getPrivateInstanceVars(key);
return privates.arr.toString();
};
Stack.prototype.print = function() {
var privates = this.getPrivateInstanceVars(key);
console.log(privates.arr);
}
return Stack;
}());
// TEST
// works - they ARE separate now
var s1 = new Stack();
var s2 = new Stack();
s1.push("s1a");
s1.push("s1b");
s2.push("s2a");
s2.push("s2b");
s1.print(); // ["s1a", "s1b"]
s2.print(); // ["s2a", "s2b"]
// works!
Stack.prototype.push.call(s1, "s1c");
s1.print(); // ["s1a", "s1b", "s1c"]
// extending the Stack
var LimitedStack = function(maxSize) {
Stack.apply(this, arguments);
this.maxSize = maxSize;
}
LimitedStack.prototype = new Stack();
LimitedStack.prototype.constructor = LimitedStack;
LimitedStack.prototype.push = function() {
if(this.size() < this.maxSize) {
Stack.prototype.push.apply(this, arguments);
} else {
console.log("Maximum size of " + this.maxSize + " reached; cannot push.");
}
// note that the private variable arr is not directly accessible
// to extending prototypes
// this.getArr(key) // !! this will fail (key not defined)
};
var limstack = new LimitedStack(3);
limstack.push(1);
limstack.push(2);
limstack.push(3);
limstack.push(4); // Maximum size of 3 reached; cannot push
limstack.print(); // [1, 2, 3]
Cons: basically none, other than remembering a little extra code
Original solution
(The first method originally posted was substantially different from what is below, but through some careless editing I seem to have lost it. It didn't work as well anyway, so no real harm done.)
Here a new object/prototype is created with every instantiation, but it borrows much of the code from the static privilegedInstanceMethods. What still fails is the ability to do Stack.prototype.push.call(s1, val), but now that the prototype is being set on the object, I think we're getting closer.
var Stack = (function() {
var privilegedInstanceMethods = {
push: function(x) {
this.arr.push(x);
},
pop: function() {
return this.arr.length ? this.arr.splice(this.arr.length - 1, 1)[0] : null;
},
size: function() {
return this.arr.length;
},
empty: function() {
return this.arr.length === 0;
},
print: function() {
console.log(this.arr);
},
};
var Stack_1 = function() {
var Stack_2 = function() {
var privateInstanceMembers = {arr: []};
for (var k in privilegedInstanceMethods) {
if (privilegedInstanceMethods.hasOwnProperty(k)) {
// this essentially recreates the class each time an object is created,
// but without recreating the majority of the function code
Stack_2.prototype[k] = privilegedInstanceMethods[k].bind(privateInstanceMembers);
}
}
};
return new Stack_2(); // this is key
};
// give Stack.prototype access to the methods as well.
for(var k in privilegedInstanceMethods) {
if(privilegedInstanceMethods.hasOwnProperty(k)) {
Stack_1.prototype[k] = (function(k2) {
return function() {
this[k2].apply(this, arguments);
};
}(k)); // necessary to prevent k from being same in all
}
}
return Stack_1;
}());
Test:
// works - they ARE separate now
var s1 = new Stack();
var s2 = new Stack();
s1.push("s1a");
s1.push("s1b");
s2.push("s2a");
s2.push("s2b");
s1.print(); // ["s1a", "s1b"]
s2.print(); // ["s2a", "s2b"]
// works!
Stack.prototype.push.call(s1, "s1c");
s1.print(); // ["s1a", "s1b", "s1c"]
Pros:
this.arr is not directly accessible
method code is only defined once, not per instance
s1.push(x) works and so does Stack.prototype.push.call(s1, x)
Cons:
The bind call creates four new wrapper functions on every instantiation (but the code is much smaller than creating the internal push/pop/empty/size functions every time).
The code is a little complicated

What are some idiomatic ways to create custom Javascript objects

I am creating a custom object to be used in some internal applications where I work. I researched some ways to go about doing this - and this is what I came out with.
function ISGrader(text)
{
this.text = text;
this.printInfo = function(){
alert("Object working " + text);
}
this.putGrade = function(score)
{
alert(score);
}
}
I believe this shows constructor-type functionality, as well as some simple starter methods that I will build on.
Is the above good practice or is there another way that is more standard?
I prefer a pattern similar to the one below. You can think of it as a 4-step approach:
(function(parent) {
// 1. Declare private variables and functions that will be
// accessible by everybody within the scope of this
// function, but not outside of it.
var doSomethingAwesome = function() { .. }; // private function
var coolInteger = 42; // private variable
// 2. Create the constructor function
function ISGrader() {
..
}
// 3. Create shared public methods on the prototype object.
// These will be created only once, and shared between all objects
// which is more efficient that re-creating each method for each object.
ISGrader.prototype.printInfo = function() { .. };
ISGrader.prototype.putGrade = function(score) { .. };
// 4. Expose the constructor to the outside world.
parent.ISGrader = ISGrader;
})(window);
The reason why everything is enclosed inside a self-executing anonymous function is to ensure the private variables we create inside don't leak outside to the enclosing scope, and to basically keep things clean.
Another benefit of declaring the constructor like this is that you can change the parent object easily from say window to a further namespaced object by changing a single word.
I prefer this pattern (IIFE), but it is purely opinion:
var ISGrader = (function (text) {
// anything declared here is "private"
var printInfo = function() {
alert("Object working " + text);
};
var putGrade = function (score) {
alert(score);
};
// put "publicly" accesible things in the returned object
return {
text: text,
printInfo: printInfo,
putGrade: putGrade
};
})(text);
It is always recommended to do it using `prototype'. This way you can also inherit it's properties and create new one.
var ISGrader = function(text) {
this.text = text;
var _privateVar = text;
this.updatePrivateVar = function(newText) {
_privateVar = newText;
alert("private variable updated");
}
}
ISGrader.prototype.text = "";
ISGrader.prototype.printInfo = function() {
alert("Object working " + this.text);
}
ISGrader.prototype.putGrade = function(score) {
alert(score);
}
var isGrader = new ISGrader("hello");
isGrader.printInfo();
// Inherit and create a new definition
var ISGrader2 = function() {}
ISGrader2.prototype = new ISGrader();
var isGrader2 = new ISGrader("hello2");
isGrader2.printInfo();
isGrader2.updatePrivateVar("hello3");
demo : http://jsfiddle.net/rkspP/3/
While not really an answer, I recommend Douglas Crockford's book JavaScript: The Good Parts as it does a good job of introducing you to the "good parts" of the language and discusses the pros and cons of the different ways to create objects in JavaScript.
You can also review this resource if you're just looking for an explanation of member visibility in JavaScript objects: http://javascript.crockford.com/private.html
If you are planning on creating multiple ISGrader objects on a single page, it's more memory efficient to stick the functions in a prototype object assigned to ISGrader like this:
function ISGrader(text) {
this.text = text;
}
ISGrader.prototype = {
printInfo: function() {
alert("Object working " + this.text);
},
putGrade: function(score) {
alert(score);
}
}

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();
}
});
}
.
.
.
}

Javascript OOP best practices? [closed]

As it currently stands, this question is not a good fit for our Q&A format. We expect answers to be supported by facts, references, or expertise, but this question will likely solicit debate, arguments, polling, or extended discussion. If you feel that this question can be improved and possibly reopened, visit the help center for guidance.
Closed 9 years ago.
I'm sick of seeing dozens of different ways of doing object oriented programming in Javascript. Can anyone just tell me which technique I should use considering I want to work on a large scale project and I want my code to be future proof?
These are just a few quick guidelines I've come up with, if anyone else has anything meaningful to add, I've set this answer as a community wiki so it should be easy enough for you to edit.
Namespace your objects to ensure they will never conflict with third party JavaScript libraries.
window['Andrew']['JS'] = {
addEvent: function(el,evName) {/*Stuff*/},
Rectangle: function(width,height) {/*Stuff*/}
};
So then you would create a rectangle object by using:
var myRect = new Andrew.JS.Rectangle(14,11);
And then your code will never interfere with, or be interfered by anybody else's Rectangle.
Use a consistent naming strategy, specifically:
Object names should be capitalized, everything else (variables, functions) should begin with a lower case character i.e.
var myRect = new Andrew.JS.Rectangle(14,11);
document.write(myRect.getArea());
Ensure everything is meaningful, i.e. verbs for methods, nouns + adjectives for parameters.
Make sure all methods and parameters are relevant to the object they belong to. e.g.
In this example, the area of the rectangle can be converted to square feet using the method inSquareFeet().
myRect.getAreaObject().inSquareFeet();
Make sure inSquareFeet is a method of the object returned by getAreaObject() and not a method of Andrew.JS.Rectangle
Use constructors, or more specifically, try as hard as possible to make sure that an object doesn't need any further initialization to be used once it has been constructed, so instead of:
var Person = function()
{
this.name = "";
this.sayHello = function ()
{
alert(this.name + " says 'Hello!'");
return this;
}
}
var bob = new Person();
bob.name = "Bob Poulton";
bob.sayHello();
try:
var Person = function(name)
{
this.name = name;
this.sayHello = function ()
{
alert(this.name + " says 'Hello!'");
return this;
}
}
var bob = new Person("Bob Poulton");
bob.sayHello();
I always use John resig's:
http://ejohn.org/blog/simple-javascript-inheritance/
It's simple and doesn't require any frameworks to function.
Because you are working on a large scale project i would suggestion a javascript framework like mootools http://mootools.net/.
It has a good class and inheritance structure.
My ideal Object for OOP is like using an Instance method with prototypes:
Example:
var Users = function()
{
var _instance;
this.prototype.getUsername = function(){/*...*/}
this.prototype.getFirstname = function(){/*...*/}
this.prototype.getSecurityHash = function(){/*...*/}
/*...*/
/*Static Methods as such*/
return { /*Return a small Object*/
GetInstance : function()
{
if(_instance == null)
{
_instnance = new Users(arguments);
}
return _instnance; //Return the object
},
New: function()
{
_instnance = null; //unset It
return this.GetInstnace(arguments);
}
}
}
Then I would always use like:
Firstname = Users.GetInstance('Robert','Pitt').getFirstname();
Username = Users.GetInstance().getUsername(); //Returns the above object.
Me = Users.New('Robert',null); //Deletes the above object and creates a new instance.
Father = Users.New('Peter','Piper'); //New Object
Me.AddFather(Father); //Me Object.
And that's the kind of road i go down when it comes to building a JavaScript OO Style architecture.
just for your information, i think YUI provides few great tutorials on this topic
//Create and define Global NameSpace Object
( function(GlobalObject, $, undefined)
{
GlobalObject.Method = function()
{
///<summary></summary>
}
GlobalObject.Functionality = {};
}) (GlobalObject = GlobalObject || {}, jQuery);
//New object for specific functionality
( function(Events, $, undefined)
{
//Member Variables
var Variable; // (Used for) , (type)
// Initialize
Events.Init = function()
{
///<summary></summary>
}
// public method
Events.PublicMethod = function(oParam)
{
///<summary></summary>
///<param type=""></param>
}
// protected method (typically define in global object, but can be made available from here)
GlobalObject.Functionality.ProtectedMethod = function()
{
///<summary></summary>
}
// internal method (typically define in global object, but can be made available from here)
GlobalObject.InternalMethod = function()
{
///<summary></summary>
}
// private method
var privateMethod = function()
{
///<summary></summary>
}
}) (GlobalObject.Funcitonality.Events = GlobalObject.Funcitonality.Events || {}, jQuery )
// Reusable "class" object
var oMultiInstanceClass = function()
{
// Memeber Variables again
var oMember = null; //
// Public method
this.Init = function(oParam)
{
oMember = oParam;
for ( n = 1; i < oMemeber.length; i += 1 )
{
new this.SubClass.Init(oMember[i]); // you get the point, yeah?
}
}
this.Subclass = function()
{
this.Init = function() { }
}
}
The strength to this is that it initializes the Global object automatically, allows you to maintain the integrity of your code, and organizes each piece of functionality into a specific grouping by your definition.
This structure is solid, presenting all of the basic syntactical things you would expect from OOP without the key words.
There are even some ingenious ways to set up interfaces as well. If you choose to go that far, a simple search will give you some good tutorials and tips.
Even setting up intellisense is possible with javascript and visual studio, and then defining each piece and referencing them makes writing javascript cleaner and more manageable.
Using these three methods as needed by your situation helps keep the global namespace clean, keep your code organized and maintains separation of concerns for each object.. if used correctly. Remember, Object Oriented Design is of no use if you don't utilize the logic behind using objects!
function foo() {
var bar = function() { console.log("i'm a private method"); return 1; };
var iAmAPrivateVariable = 1;
return {
publicMethod: function() { alert(iAmAPrivateVariable); },
publicVariable: bar()
}
}
//usage
var thing = foo()
This is a functional approach, and has a great deal more going for it (such as encapsulation) then anything else you are going to see
In a general way, you shouldn't be doing OO in javascript, it isn't that great a language for it for a great many reasons. Think scheme with squiggly brackets and semi-colons, and you will start writing the language like the pros do. That being said, sometime OO is a better fit. In those cases, the above is typically the best bet
to bring inheritance into the mix
function parent() {
return { parentVariable: 2 };
}
function foo() {
var bar = function() { console.log("i'm a private method"); return 1; };
var iAmAPrivateVariable = 1;
me = parent();
me.publicMethod = function() { alert(iAmAPrivateVariable); };
me.publicVariable = bar();
return me;
}
This makes things a tad more complected, but accomplishes the desired end result while still taking a functional approach to OO concepts (in this case, using decorator functions instead of real inheritance). What I like about the whole approach is we are still really treating objects the way they are intended to be in this kind of language -- a property bag you can attach stuff to at will.
Another note is this is wildly different then what you will see most of the time in most of the jobs you will ever work at, and often is very hard to explain a) what is going on, and b) why it is a good idea to coworkers.
I use such a pattern and recommend to you to use it too:
function Person(firstname, lastname, age)
{
var self = this;
var _ = {};
// Private members.
var firstname = firstname;
var lastname = lastname;
var age = age || 'unknown';
// Private methods.
function first_letter_to_uppercase(str) {
return str.charAt(0).toUpperCase() + str.substr(1);
}
// Public members and methods.
_.get_age = function()
{
return age;
}
_.get_name = function()
{
return first_letter_to_uppercase(firstname) + ' ' +
first_letter_to_uppercase(lastname);
}
return _;
}
var p = new Person('vasya', 'pupkin', 23);
alert("It's " + p.get_name() + ', he is ' + p.get_age() + ' years old.')
You can try with a simple, usefull and quick object:
var foo = {
foo1: null,
foo2: true,
foo3: 24,
foo4: new Array(),
nameOfFunction1: function(){
alert("foo1");
},
nameOfFunction2: function(){
alert("foo2");
},
}
To use this, you have to create an instance of this object and use like a object in java:
foo.nameOfFunction2();
Also you can check this link to other solution: http://www.javascriptkit.com/javatutors/oopjs.shtml
I hope that answer your question.

Categories

Resources