Javascript class for enforcing JSON structure - javascript

Relatively new to JavaScript, so wondering what is the best approach to achive the below requirement.
I wanted to create JSON object (RPC request object), and need to enforce some structure. As I learn, JS is dynamic language hence I can add any type to an object at any time. But, I like to define a class, which I can populate to construct the JSON request.
var RecReq = {
ID:{},
HeaderLevel:{},
Content:{} //Content object goes here
},
HeaderLevel = {
HeaderID:{},
Note:{}
},
Content = {
Item: [] //Array of Item goes here
},
Item = {
IDs:[]
};
function ReceiveObj() {
this.RecReq = RecReq,
this.HeaderLevel = HeaderLevel,
this.Content = Content,
this.Item = Item
};
return new ReceiveObj();
I am sure many things wrong with the above code. I don't think the object is created with the arrays initialized.
On the returned object, I cannot do push() operation to insert an iten onto Content.
How would you approach this. Do you create an object on the fly, or better to define an object which enforces some structure.

If, as your code suggests, you want your instances to inherit the outer object, one approach would be to assign the prototype of the 'class' (be careful of thinking in class terms in JS - it's not a class in the Java etc sense) to the object.
var obj = {
prop_1: 'foo',
prop_1: 'bar'
}
function Something() {
alert(this.prop_1); //alerts "foo"
}
Something.prototype = obj;
var something = new Something();
This is just one way. There are many patterns for controlling inheritance (and other patterns that would achieve what you want without even going near the concept of inheritance).
As for push() not working, in your code, Content is an object, whereas push() is a method of the Array prototype. In other words, you can push() into an array only. Perhaps you meant Content.Item, which IS an array.
Lastly, I would avoid capitalising names. In JavaScript, this tends to be done only with functions that are used in class simulation (like your ReceiveObj), to denote that they should be instantiated, not merely invoked.

Related

Javascript - Prototyping on DOM elements

I'm building custom libraries to handle GUI and creating divs and stuff programatically. I also want to extend these objects with children and methods to do something like this:
Function CustomElement() {
this = document.createElement('div');
///--------
Some custom properties
///--------
}
CustomElement.prototype.customMethod = function(args) {
///--------
Some code here
///--------
};
var elem = new CustomElement();
document.body.appendChild(elem);
elem.customMethod(args);
I've thoroughly searched for an answer but found none. How can I accomplish this?
Note: I'm posting from my cell phone. Please excuse me if the code looks awful. I'll correct it as soon as I have access to a PC.
I appears you are confused between classical languages such that you are probably use to, and prototypical like languages such as Javascript.
Also, in your example, assigning the value of this is an invalid statement.
In Javascript, instead of creating children of a super class, we create objects that inherit the properties of other objects through the prototype chain. Still with me? This means that your customMethod is not technically a method, rather it is a property called customMethod which has the value of a function object.
Every constructor object (which is just a fancy name for your CustomElement function) has a magical property named prototype as you have discovered. Objects don't have this property, but they do have an implicit reference to their constructor's prototype object. This means you can call your customMethod as if it were a property of elem, but it is really a property of the constructors prototype object. So I guess you could say the prototype object is kind of like a parent and the object is kind of like a child (although this is incorrect terminology). This prototype object may also again have an implicit reference to it's constructor prototype, which may reference it's constructor prototype... and so on. That's why its called the prototype chain.
So to answer your question:
I also want to extend these objects with children and methods... How can I accomplish this?
For a suggestion to emulate child like inheritance, see below. However, your library requires a different approach...
A common angle of attack is to create a constructor which creates a new object, with a new Element object as a property of that object. For example:
function CustomElement(doesLikeTrains) {
// keep element in this property
this.nativeElement = document.createElement('div');
// other properties are separate
this.likesTrains = doesLikeTrains;
}
// these are also separate
CustomElement.prototype.doesLikeTrains = function() {
return this.likesTrains;
};
// Lets make objects!
var elem1 = new CustomElement(true);
var elem2 = new CustomElement(false);
// use object property and inherited properties
// we can still use the element ok
document.body.appendChild(elem2.nativeElement);
elem1.doesLikeTrains(); // prints true
elem2.doesLikeTrains(); // prints false :(
The DOM element assigned to the nativeElement property. This means you may add other properties without changing the native element object, but still have access to them. Both elem1 and elem2 inherit the same doesLikeTrains property with the same value, but each have their own likesTrains property, which is initialised in the constructor, and can keep a value specific to the object instance.
The advantage of this is that you could change the doesLikeTrains function to always return true, and because all objects created using your CustomELement constructor inherit the same prototype, all objects would then like trains regardless!
How would one create children like objects?
To emulate a child structure, consider...
function CustomOtherElement(likesTrains, runsOnCoal) {
// create new object and inherit from CustomElement
function EmptyConstructor() {}
EmptyConstructor.prototype = new CustomElement(likesTrains);
// add extra stuff to CustomOtherElements only
EmptyConstructor.runsOnCoal = runsOnCoal;
EmptyConstructor.isTrainSuperFan = function () {
return "Hoot hoot, chugga chugga!";
}
// return the new object
return new EmptyConstructor();
}
// now you can do
var elem3 = CustomOtherElement(true, true);
document.body.appendChild(elem3.nativeElement);
elem3.doesLikeTrains(); // true
elem3.isTrainSuperFan(); // "Hoot hoot, chugga chug!"
The above uses this new CustomOtherElement constructor to make an object that inherits CustomeElement and then add some new properties to this new object. Now you can use both the inherited properties from CustomElement and the new ones created on elem3! Happy Javascripting!
Resource: ECMAScript Language Specifications 5.1 section 4.2.1 (Objects)
Consider the approach sometimes called "parasitical inheritance". In this pattern, you write a constructor function, but return something else after adding methods/properties to it, such as
function CustomElement() {
var elt = document.createElement('div');
///--------
Some custom properties
///--------
elt.customMethod = function(args) {
///--------
Some code here
///--------
};
return elt;
}
var myCustomElement = new CustomElement();
This can be simpler, and more reliable, than trying to subclass HTMLElement, which can be a delicate operation, or wrapping the underlying HTML element, as other answers suggest.
Some might complain that the above approach is fat or slow because the "prototype" methods are being placed on each instance. However, that's something that's not really an issue on modern machines and browsers.
In any case, once we've come this far, we need to ask why we are trying to use constructors and new at all, when we can simply say:
function makeCustomElement() {
var elt = ...;
// set custom properties
// set custom methods
return elt;
}
var myCustomElement = makeCustomElement();
Defining a "subclass" is as simple as:
function makeCustomElementSubclass() {
var elt = makeCustomElement();
// set custom properties and methods
return elt;
}
In none of the cases above are prototypes being used (except methods on the built-in prototype such as HTMLElement). They're not really necessary. As I understand it, this is the direction in which mega-guru Douglas Crockford has gravitated in his style. Many cases where we see people using prototypes, it is a matter of "let me figure out a way to do this using prototypes, because they exist and I sort of think I'm supposed to be using them", or "let me figure out a way to do this using prototypes because they sort of behave like the classes I'm used to from C++/Java/C#", or "let me use prototypes to do this because putting methods once on prototypes is so much more efficient than putting them on each object"--but none of these are compelling reasons.

How to communicate different levels in the same javascript object

I am trying to namespace my jQuery app.
Example:
var app = {
data : {
data1: ''
},
fn: {
setData1: function(value){
app.data.data1 = value
}
}
}
This works, but is there a better solution which doesn't use the full path? Moreover, is this a good code structure for a medium-sized application?
Javascript does not have syntax for specifying shortcuts to a parent element in a nested literal object definition. And, in fact, Javascript a nested object inside another object could have been defined anywhere and the reference assigned into the object and could be assigned into many objects so there is no real such thing as a parent at runtime as far as Javascript is concerned. Javascript just doesn't work that way.
As such, if you want to reference another element of the object that is not below it, then you will have to use the full path of object names starting from the top of the object.
As to whether this is a good way to do this, that is entirely context-specific. At first glance (and with no other context supplied), I don't see why you need the fn or data levels in your object. Data properties and methods can be at the same level and that is commonly done without adding extra levels. You will find that extra levels that aren't necessary just increase the amount of typing in your code and do not improve performance. You should give your methods and data properties meaningful enough names that it's very clear what they are and what they are used for. A name like data1 is not a particularly good example.
In addition, there is generally not a reason to make a setData1() method for a public data1 property, but if you put them at the same level, you can do use the this pointer in the method which will be set to app if someone calls app.setData1():
var app = {
data1: ''
setData1: function(value){
this.data1 = value;
}
}

Does this method have a method?

I have a few questions about some code I've come across. You're not required to understand the framework or it's API as my only issue is having a better understanding of some concepts.
I understand that in the line below, the variable polygonCollisionSpite is being assigned the return value of game.add.sprite() which I'm assuming is an object.
var polygonCollisionSprite = game.add.sprite(400,128,'check');
What's confusing to me is what appears to be method chaining? I'd understand a regular method like game.add() but game.add.sprite(), how does that look in the object? this.game.add.sprite = function(){} ?
Then I also came across
scoreText = game.add.text(10, 10, 'Hit Space to Restart Demo');
scoreText.font = 'Arial Black';
scoreText.fontSize = 16;
scoreText.stroke = '#000';
scoreText.strokeThickness = 3;
scoreText.fill = '#fff';
This looks like properties are being added to the object returned and assigned to "scoreText". How are properties able to be added without the usage of the .prototype method?
What might the object being returned to scoreText look like?
Finally, an unrelated but simple question: What's the benefit of assigning a fired function to a variable like:
myvar = test();
Thanks
What's confusing to me is what appears to be method chaining?
There is no chaining there.
Chaining is when a method returns this so foo.bar().baz() has the value of foo as the value of this in both functions.
game.add.sprite(400,128,'check');
This is just accessing properties of an object.
An object can have a property:
someObject.someProperty
The property can have a value
someObject.someProperty = someOtherObject;
That value can be an object, which can have its own properties.
This looks like properties are being added to the object returned and assigned to "scoreText".
The object returned is assigned to scoreText. Properties are then added to that object.
How are properties able to be added without the usage of the .prototype method?
Adding properties to the prototype object makes them available down the inheritance chain when a new object is created from the constructor.
You can add properties to any object.
Most JavaScript that adds properties to something does it to an object directly and doesn't touch the prototype object.
var myPeople = {};
myPeople.john = { name: "John Smith", address: "27 Witherson Ave" };
myPeople.daisy = { name: "Daisy Mannors", address: "19 Cumberbund Rd" };
What might the object being returned to scoreText look like?
There isn't really anything in the code you've provided that could help us infer that. (Other then the properties you explicitly add afterwards).
Finally, an unrelated but simple question: What's the benefit of assigning a fired function to a variable
The same as using a variable for absolutely anything else. You can reuse it, you can change it, you don't need to type out everything needed to recreate it everytime you want to use it.
What I would assume is going on here is game.add.sprite works a little bit like the following:
game.add.sprite = function (options) {
// create instance of Sprite
var inst = new Sprite(options);
// add inst to some entity pool
game.objects.push(inst);
// return for use
return inst;
};
This way, both you and the library/framework has access to this object (inst), and any changes you make, the library/framework is aware of as well.

Pushing complex hierarchies into an observableArray creates repeated instancies

In trying to come up with a basic model to handle all the similar entities for the application domain I'm working on, I created:
A basic object (Entity): that has some shared properties and initializers, setup as Prototype
A product object (Product): that "inherits" from Entity. And contains a list of "Variants"
A variant object (Variant): that "inherits" from Entity.
Product.prototype = new Entity();
Variant.prototype = new Entity();
When I run this, something weird happens: the "variants" list from the "product" object, ends up containing two elements, which is fine, but instead of these being two separates instances of "Variant", they point at the same memory space.
I've done some debugging (alert based), to ensure that, during the 'for loop' that fills the observableArray, things look fine.
var Product = function (data) {
var initial = data || {};
this.variants = ko.observableArray();
this.init(initial);
if (initial.variants != null) {
for (var i = 0; i < initial.variants.length; i++) {
// NOTE: this is the misterious line. Creating two instances
// of 'new Variant', ends up pushing a single instance.
this.variants.push(new Variant(initial.variants[i]));
//-----------------------------------------------------------
alert(this.variants()[i].name());
}
}
I asume I'm missing some Javascript basics to figure out what am I doing wrong.
Heres the complete sample at JsFiddle.
If you put observables on a prototype, then they end up being shared across all instances rather than being their own separate observables. An observable is a function that caches its value internally. So, in this case, every instance has a copy of that same function.
Generally, you would want to avoid putting observables on the prototype, although you can certainly put any other functions (general handlers, subscription callbacks, and computed observable read/write functions).
If you want to create a structure that inherits from another that has observables, then could choose to use one of the various "mix-in" type strategies.
For example, you could apply the base constructor to the sibling object.
var Product = function(data) {
Entity.call(this, data); //call the Entity constructor to add observables, etc.
//do other Product stuff here
};
You can then make the Product prototype equal the Entity prototype or better make the Product prototype have the Entity prototype in its chain like:
Product.prototype = Object.create(Entity.prototype);
If you are supporting older browsers, then look for an Object.create shim.
Updated sample: http://jsfiddle.net/rniemeyer/7AnAz/

What is the use of creating a class in javascript, if I can insert any attritube to an object any time

Consider the below code.
I created an empty object. And am adding var1,var2,var3 without declaring them.
var har = new Object();
har.var1 = "Var1";
har.var2 = "Var1";
har.var3 = "Var1";
alert( har.var1 );
If I can do this, then why do I need to create a Class and fix the attributes when I can introduce new attributes anytime?
Why would you even need to use objects in the first place? Non-object-oriented languages are already Turing-complete, so everything you can accomplish with objects you can also do without them.
What you're showing in your example is not really an object, but just a dictionary. In cases like this, where you only need to keep several related properties together, anonymous unprototyped objects like the one you're using are the de-facto standard approach (though it is customary to initialize them with the shorthand syntax, e.g. var har = {}). It is an object, since it uses the object data structure, but it is not object-oriented.
Actual objects, in contrast, not only define data, but also the operations that you can perform on that data. Objects have not only properties, but also methods which work on these properties. These properties are usually defined in the object prototype (which you're calling "class", but Javascript is not a class-based language, but a prototype-based one). All methods defined in the prototype are shared between all instances of that prototype.
function Counter() {
this.counter = 0;
}
Counter.prototype.increment = function() {
this.counter++;
alert(this.counter);
}
var c1 = new Counter();
var c2 = new Counter();
c1.increment(); // alerts 1
c1.increment(); // alerts 2
c2.increment(); // independent from c1: alerts 1 again
Each instance is still a dictionary, as in your example (and you can even still add more properties to them, they are not "fixed" by having a constructor and prototype), but now it can also perform tasks on its properties. This can be done your way as well:
c1 = {
counter: 0,
increment: function() {
this.counter++;
alert(this.counter);
}
}
c2 = {
counter: 0,
increment: function() {
this.counter++;
alert(this.counter);
}
}
You can see, however, that if you need two counters, without using prototypes you will need to duplicate your entire object definition. This will be cumbersome to write and maintain, and each increment function will be defined separately, thus it will also waste memory.
That said, in cases where you need an object that you know you'll only ever need one instance of, it makes no sense to define a constructor and a prototype for it. Such objects are usually regarded as namespaces instead of actual objects.
Appendix: Dictionaries vs Objects
A dictionary is a data structure which holds named elements. Besides "dictionary", they are also called associative arrays or hashmaps. Objects in Javascript are implemented as dictionaries — each property is a named element in the dictionary. In addition to a plain dictionary, objects also have a prototype, which is kind-of like a parent object — when you look up a named element in the dictionary and it is not there, it is automatically searched for in the prototype as well. This way, default properties and methods are defined only once in the prototype, and do not need to be copied into each instance. (The prototype of an object is often visible as the instance.__proto__ property, though this is non-standard and deprecated even in browsers that support it; the actual prototype is defined as an internal, non-accessible property by the standard)
So, Javascript objects are actually dictionaries. When you want to use a plain dictionary to store some related properties together, there is no separate syntax in Javascript to create a dictionary that is not an object, so you create an instance of the base Object type to hold your dictionary (it does not matter if you do var dict = new Object or var dict = {}, the result is the same); thus, dictionaries that you use in your code are also objects.

Categories

Resources