I want to pull a tree structured set of objects from a web service represented with JSON
When I unpack that, I'll wind up with a structure which uses vanilla Javascript objects. What I'd like to be able to do is bind each node to a specific class, so that method calls become available on each node of the tree.
My solution, using jQuery .extend()
Here's a simplified example which illustrates the approach.
I might define a simple class using jQuery .extend() as follows...
MyNode= function() {
this.init();
}
$.extend(MyNode.prototype, {
init: function() {
// do initialization here
},
getName: function() {
return this.nodeName;
}
});
Now given a simple object like this
var tree={
nodeName:'frumious',
nodeType:'MyNode'
}
I can make the object appear to be an instance of the desired nodeType with
$.extend(tree, eval(tree.nodeType+'.prototype'));
Note that I want the object to declare the class name, so I've used eval to locate the appropriate prototype for that class. (Thanks to Rob W for suggesting window[tree.nodeType].prototype as a better alternative)
Now I can do things like alert(tree.getName());
Better ways?
I write StackOverflow questions and find the act of describing it in enough detail to avoid a downvote is enough for me to solve it myself. This was no exception, but I'd be interested to hear of any more elegant approaches to this problem. This solution gets the job done, but I can't help but feel there must be other approaches...
I'd get rid off eval, and use:
$.extend(tree, window[tree.nodeType].prototype);
If MyNode is a local, but known variable, add it to an object, for reference. Eg:
var collection = {};
collection['MyNode'] = MyNode;
$.extend(tree, collection[tree.nodeType].prototype);
Alternatively, if the structure of the JSON is solid, I recommend a custom JSON parser, which also allows you to validate properties prior addition.
Related
I come from a C# background. I've been working a lot with JavaScript lately. On a new app, I have a mysql/php back end. I'm going to be passing a lot of "types" back and forth.
So in my data base, I have several tables like
table1
id, fieldx,fieldy,fieldz
table2
id, fielda,fieldb,fielc
In c# I would definitely write classes for all those in the code. Which led me to implement things like so (in my JavaScript app):
function table1(id, x,y,z){
this.id=id;
this.x=x;
this.y=y;
this.z=z;
}
After about 6 tables worth of that, it suddenly occurred to me that maybe there was no point at all in making these classes.
So my question is, in a JavaScript app, do I use "classes" for data types? or should I just "document" which fields/types are expected and so in the code instead of
a.push(new table1(5,1,2,3));
I would just have
a.push({id:5,x:1,y:2,z:3});
This may seem like a preferences question but it's a fundamental language question that I have as I try to understand how to model my app's data in JavaScript. Is there any advantage of the classes (with only data fields) or is it just a mistake. Thanks.
It depends,
Note: Most of the programmers coming from a strong OO language will have trouble like you in regard to JavaScript's functional behavior (you are not alone).
If you want to create something closer to C# I would do the following:
function Table1(id, x, y, z) {
this.id=id;
this.x=x;
this.y=y;
this.z=z;
}
Table1.prototype.mySpecialTable1Method= function()
{
console.log(this.id);
};
Implementation:
var t = new Table1(1, 2, 3, 4);
t.mySpecialTable1Method();// outputs: 1
If you need to have methods that interact with the (soon to be) objects then I would definitely go with the code above. In addition it will make it clear when working with the objects that are related to a specific 'type' (naming the data).
But if your objects do not require any special "treatment" then I don't see any problem to use normal js object literals and pass them along (probably good for small projects).
Something along the lines:
var table1 = {};
table1.id = 1;
table1.x = 2;
table1.y = 3;
table1.z = 4;
console.log(table1.id); //outputs: 1
Extra reference:
http://www.youtube.com/watch?v=PMfcsYzj-9M
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Introduction_to_Object-Oriented_JavaScript
Update:
For the sake of readability and scalability and the point that you are coming from C# you may want to stick to the "class" implementation just because it will define the correlation between the raw data and the objects you are working with.
There is a good chance that you are going to work with some data that will probably be messy and unorganized.
MVC may be the solution for you. It tries to bring some order to the chaos that you are expecting. I recommend to check out some of them like: AngularJS or Ember.
Another solution may be reactive js - but mostly if you are going to interact with the DOM according to your data (ReactJS, and Facebook's React as some good ones).
As a note for security, I would like to add that mapping the data closely to the db isn't a best practice but its your call.
Javascript is a funny language, and there are plenty of ways to do things. An Object is an Object in Javascript with or without a name. {} is just a short-hand way to create one.
If you are going for readability, then your initial example would be the way to go.
If you just want to get the block of data into an array, then your second example is appropriate. Personally, I would use your later example if it is just data.
If you are using functions and what not as well as data storage, and plan on reusing it several times in your code, then yes, define your object and call it appropriately.
JavaScript has no classes, it is a functional language and a function is a first class citizen in js meaning that a function is an object.
From your example I can see that your intention for classes is simply to pass data and using json is perfect for this.
at the moment I'm writing a small app and came to the point, where I thought it would be clever to clone an object, instead of using a reference.
The reason I'm doing this is, because I'm collecting objects in a list. Later I will only work with this list, because it's part of a model. The reference isn't something I need and I want to avoid having references to outside objects in the list, because I don't want someone to build a construct, where the model can be changed from an inconsiderate place in their code. (The integrity of the information in the model is very important.)
Additional I thought I will get a better performance out of it, when I don't use references.
So my overall question still is: When should I prefer a clone over an reference in javascript?
Thanks!
If stability is important, then clone it. If testing shows that this is a bottleneck, consider changing it to a reference. I'd be very surprised if it is a bottleneck though, unless you have a very complicated object which is passed back and forth very frequently (and if you're doing that it's probably an indication of a bad design).
Also remember that you can only do so much to save other developers from their own stupidity. If they really want to break your API, they could just replace your functions with their own by copying the source or modifying it at runtime. If you document that the object must not be changed, a good developer (yes, there are some) will follow that rule.
For what it's worth, I've used both approaches in my own projects. For small structs which don't get passed around much, I've made copies for stability, and for larger data (e.g. 3D vertex data which may be passed around every frame), I don't copy.
Why not just make the objects stored in the list immutable? Instead of storing simple JSON-like objects you would store closures.
Say you have an object with two properties A and B. It looks like that:
myObj = {
"A" : "someValue",
"B" : "someOtherValue"
}
But then, as you said, anyone could alter the state of this object by simply overriding it's properties A or B. Instead of passing such objects in a list to the client, you could pass read-only data created from your actual objects.
First define a function that takes an ordinary object and returns a set of accessors to it:
var readOnlyObj = function(builder) {
return {
getA : function() { return builder.A; },
getB : function() { return builder.B; }
}
}
Then instead of your object myObj give the user readOnlyObj(myObj) so that they can access the properties by methods getA and getB.
This way you avoid the costs of cloning and provide a clear set of valid actions that a user can perform on your objects.
I've run into a javascript question that I don't know how to resolve. I'm grouping a bunch of variables and methods into a DocManager object. Everything related to managing "documents" in my application lives here. Basically, the DocManager acts like a class with a single instance.
Ex:
var DocManager = {
doc_list : [], //Array of documents containing content and metadata
doc_index : 0, //Index of the currently visible document
loadDocList : function( collection_id, csrf_token, seq_list ){
...
},
showDocument : function(seq_index){
...,
},
...
};
Now I've run into a situation where I'd like to subclass DocManager for use on different pages with different controls. I need to add some methods and overwrite others. Most of the functionality the object will stay the same.
What's the easiest way to do this? I know javascript has a class/prototyping syntax for full-fledged object-orientation, and others have built OOP frameworks for js, but that seems like overkill for this situation. I'd prefer to not learn a lot of new syntax to carry out this simple kind of object orientation. What would you recommend?
You can simply overwrite the functions you have assigned to it.
YourDocuManager.showDocument = function(index, newindex, whatever) {
....
}
from that moment it'll use the new function assigned.
I'm developing a javascript library, composed by a main object, that works as a static Class and contains various objects that do the same thing.
I am having trouble finding the best way to refer to the objects in the documentation, as i am using jGrouse and it refers to them as Classes, like:
public Class myLibrary
None of these objects and it's children will have any primitive type variables nor will have any factory pattern associated so, they are not to be reinstantiated.
I can't show you a live example, but i'll try to put here an analogous one:
var myLibrary = {};
myLibrary.methodOne = function(){ ... };
myLibrary.methodTwo = function(){ ... };
// this is a sub-library that will encapsulate methods for Array type operations
myLibrary.Array = {};
myLibrary.Array.forEach = function(array, function(item));
(...)
// this is a sub-library that will encapsulate methods for Event type operations
myLibrary.Events = {};
(...)
So, i don't think it's correct to refer to myLibrary, myLibrary.Array and myLibrary.Events as Classes, for the obvious reason that they are not meant to be instantiated.
I reject the idea to call them Static Classes as Javascript isn't design to work with static classes per se.
I think Object and Inner Object or Static Object may not be the way to go also.
I'm looking for the best way to identify them in my public documentation, as for not to confuse unexperienced programmers nor insult the more advanced developers.
Any help?
thanx
Your probably looking for the term "namespace".
You really shouldn't worry so much about the correct word. The are all far too vague and have completely separate meaning is several different meanings in JavaScript sub cultures.
The important thing to say in documentation is that "The Event has these methods".
I want to see the method signatures, I want to see a high level description of what they do and I want to see an example.
Coming from mootools and JAVA, mootools class implementation is a real nice way to structure my code, plus I can have some nice features like extending, implementing and so on. Starting with jquery I found my self writing $.fn plugins that cant use code of other plugins. Plus it seems no good idea to use the plugin structure for complex stuff that hasn't much to do with DOM Elements. Is there a better way then $.fn? What do you recommend to structure my code using jquery.
This is a tough question to answer.
JavaScript's incredible flexibility's downside is that every programmer and his brother-in-law has a different way of doing things.
The downside of pulling in a library for doing "Class" based OOP in JavaScript (Prototype library, Moo, Joose, JS.Class, Base2, etc.) is that you immediately cut down on the number of fellow JavaScript programmers who can read your code.
Obviously, jQuery encourages you to think in terms of "collections." A collection is what you get back from a $() or jQuery() call. John Resig once considered adding a class system to jQuery, but finally decided against it. I think he's said that he's never needed a real "Class" system in JavaScript programming.
For all but the largest JS projects, I'd say forget about a Class system. Leverage JS's incredible object and array system (including literals). Namespace heavily (variables and methods alike).
I've had a lot of luck using arrays of objects for most situations I'd normally use Classes for.
An interesting extension of the jQuery collection concept is in Ariel Flesler's jQuery.Collection plugin here. It lets you treat "normal" data much as you would treat DOM data in jQuery.
I recently started using Underscore.js, which gives you a lot of functional tools to treat your data as collections.
What you generally need are mechanism for code extension and packaging.
For the former, I use the pseudo class-based default oo mechanism, sometimes with a helper function to make inheritance easier:
Function.prototype.derive = (function() {
function Dummy() {}
return function() {
Dummy.prototype = this.prototype;
return new Dummy;
};
})();
function Base() {}
function Sub() {}
Sub.prototype = Base.derive();
The latter can be achieved by namespacing via self-executing functions. It's even possible to fake import statements:
// create package:
var foo = new (function() {
// define package variables:
this.bar = 'baz';
this.spam = 'eggs';
// export package variables:
this.exports = (function(name, obj) {
var acc = [];
for(var prop in obj) {
if(obj.hasOwnProperty(prop))
acc.push(prop + '=' + name + '.' + prop);
}
return 'var ' + acc.join(',') + ';';
})('foo', this);
});
// use package:
(function() {
// import package variables:
eval(foo.exports);
alert(spam);
})();
jQuery isn't really meant to be used for structuring your code. It's meant to be a tool that you use from your other code, not a way of life.
The rest of your code should be written whatever way you like. Just use jQuery when you want to do DOM manipulation, Ajax calls, cross-browser events, etc.
You may want to learn how to use the .prototype property to put some of your code into "classes", so that you can reuse the same code in different places, by just creating a new instantiation, basically.
You can also put code into objects so that you have a unique namespace, so it is easier to share related objects amongst different projects.
Basically you will be structuring your code as you do for straight javascript, but jQuery abstracts out some of the common functionality so you don't have to worry about browser issues, but it is just a helper, it really doesn't provide a framework as much as just making some concepts simpler. For example, rather than using onclick I tend to use .bind('click', ...) but that is if I want to have the potential of more than one event hander on an element.