Object Oriented Javascript vs. Pure jQuery and .data storage - javascript

My current style of programming is OO javascript using the Class.extend function by John Resig: http://ejohn.org/blog/simple-javascript-inheritance/
This has been fine but I find myself writing numerous setters and getters that only get used on init. Also, it seems to lead to memory leaks in IE when storing instances of these objects in an array for later use.
I am starting to favor smaller, cleaner, and more readable code over the seemingly overkill OO approach. My idea is to now just base everything off the dom using jquery and storing data properties using the .data method. For example, instead of creating an instance of a new Tweet object, you would simply add a div to the dom with class tweet and simply add the properties like author, timestamp, reply to, sent from, etc. in the .data cache for that dom element.
What do you think of this less structured approach when creating instances of things such as items in a stream like twitter? Is OO and prototypal inheritance the best approach or is strict dom manipulation better?

I am doing something similar. I took the OO javascript approach. But instead of using arrays i use a key value object. The key is a unique dom element id, the value is the object itself. it looks something like this.
for example:
var collection = {};
var $domEl = jQuery; // jquery dom element
var myClass= new MyClass($domEl); // class instance
// add to collection
collection[$domEl.attr('id')] = myClass;
// remove
delete collection[$domEl.attr('id')];
Really it depends on the complexity of your objects. A strictly .data approach would need to rely on plugins for all of the related methods, and then store data in the elements data. I have many methods that are not related to strictly element interaction, so i keep the methods and data in the class.

My brain tells me that the very structured Javascript that doesn't rely on the DOM manipulation and calling in and out of it with jQuery would be ideal.
However, I just wrote an HTML5 web app that runs offline using the built in SQLlite and did it using primarily .data and storing information in divs and getting them out of there. It was simple, clean, and easy but for some reason didn't feel right.
But it worked well.

Related

caching object in DOM vs javascript variable

I've recently looked at some front end js code.
(1) In some cases the code creates a new JavaScript object from a JSON received from the back end. Then the newly created object is stored in a cache (say a map). This way the object would be cached on the front end for later use.
(2) I've also seen instances when the new JavaScript object (called eventObject here) is stored in the DOM like this: $(this).data('eventObject', eventObject);
Does it matter which way you store the data? I would personally cache eventObject in a JavaScript cache object (ie make your own cache class or a map). Isn't it simpler to cache like this than mess with the DOM and then you have to remember where you put what?
In my searches I've looked at XML DOM vs Object in Javascript
Isn't it simpler to cache like this than mess with the DOM and then you have to remember where you put what?
jQuery's data method actually doesn't mess with the DOM, it is just a convenient way to reference data objects by DOM nodes.
Of course, if you "have to remember whery you put it" the DOM references are not the best way to reference your objects. If a simple cache object seems cleaner to you, it probably will be cleaner.

How to "correctly" create an object which inherits from Element?

I am writing an HTML5 application that involves a lot of XML manipulation, part of this manipulation involves comparing the versions of two different XML Elements.
What I need is for every Element, Attr, and TextNode (all of which inherit from Node, AFAIK) object that gets created to have associated version information, but still be able to behave like a normal Element, Attr, or TextNode. The current working solution I am using to store the version information, is the following:
Node.prototype.MyAppAnnotation = {
Version : null
};
Now, I understand that augmenting built-in types is considered bad form, but beyond this technique, I'm at a loss for how to get the desired functionality. I don't think I can encapsulate the Node in a wrapper because I need the Node related properties and functions exposed on the wrapper. I might be able to write some sort of pass-through functions for the wrapper, but that seems really clunky.
I feel that because the app I'm writing is an HTML5 app, and as such only has to run on the most modern browsers (all of which support the augmentation of built-ins), makes this technique appropriate. Also, by providing a sufficiently obscure name to my augmentation object, I can avoid all naming collisions (except for intentional collisions). I've also explored inheritance-based solution using Google's Closure library. However, it appears that because Element, Node and TextNode don't have direct constructors (i.e. they're created off of a Document object), this technique will not work either.
I was wondering if someone could either a) recommend an elegant way of achieving this effect without augmenting Element, or b) provide a compelling reason for why I shouldn't break the "don't augment built-ins" rule in this case.
Many Thanks,
Jarabek
Your idea is theoretically valid, but there's a weird feeling I get when reading about it.
First of all - you don't have to augment any prototypes. If you just do somedomnode.myweirdname='foo' it will become a field of that object. That's what javascript does ;)
So when there is no version you'll get undefined instead of null.
But, if you want to add more functionality or wrap dom node in anything - there's a bit of history of doing that. Most of that history is dominated by stuff like jQuery :)
Just create an object that has a field containing the node. And then you can access it really simply:
myobject.node
And create the object with some constructor or just factory function:
var myobject = createDomNodeWrapper(domnode)

I want to stop using OOP in javascript and use delegation instead

After dabbling with javascript for a while, I became progressively convinced that OOP is not the right way to go, or at least, not extensively. Having two or three levels of inheritance is ok, but working full OOP like one would do in Java seems just not fitting.
The language supports compositing and delegation natively. I want to use just that. However, I am having trouble replicating certain benefits from OOP.
Namely:
How would I check if an object implements a certain behavior? I have thought of the following methods
Check if the object has a particular method. But this would mean standardizing method names and if the project is big, it can quickly become cumbersome, and lead to the java problem (object.hasMethod('emailRegexValidatorSimpleSuperLongNotConflictingMethodName')...It would just move the problem of OOP, not fix it. Furthermore, I could not find info on the performance of looking up if methods exist
Store each composited object in an array and check if the object contains the compositor. Something like: object.hasComposite(compositorClass)...But that's also not really elegant and is once again OOP, just not in the standard way.
Have each object have an "implements" array property, and leave the responsibility to the object to say if it implements a certain behavior, whether it is through composition or natively. Flexible and simple, but requires to remember a number of conventions. It is my preferred method until now, but I am still looking.
How would I initialize an object without repeating all the set-up for composited objects? For example, if I have an "textInput" class that uses a certain number of validators, which have to be initialized with variables, and a class "emailInput" which uses the exact same validators, it is cumbersome to repeat the code. And if the interface of the validators change, the code has to change in every class that uses them. How would I go about setting that easily? The API I am thinking of should be as simple as doing object.compositors('emailValidator','lengthValidator','...')
Is there any performance loss associated with having most of the functions that run in the app go through an apply()? Since I am going to be using delegation extensively, basic objects will most probably have almost no methods. All methods will be provided by the composited objects.
Any good resource? I have read countless posts about OOP vs delegation, and about the benefits of delegation, etc, but I can't find anything that would discuss "javascript delegation done right", in the scope of a large framework.
edit
Further explanations:
I don't have code yet, I have been working on a framework in pure OOP and I am getting stuck and in need of multiple inheritance. Thus, I decided to drop classes totally. So I am now merely at theoretical level and trying to make sense out of this.
"Compositing" might be the wrong word; I am referring to the composite pattern, very useful for tree-like structures. It's true that it is rare to have tree structures on the front end (well, save for the DOM of course), but I am developing for node.js
What I mean by "switching from OOP" is that I am going to part from defining classes, using the "new" operator, and so on; I intend to use anonymous objects and extend them with delegators. Example:
var a = {};
compositor.addDelegates(a,["validator", "accessManager", "databaseObject"]);
So a "class" would be a function with predefined delegators:
function getInputObject(type, validator){
var input = {};
compositor.addDelegates(input,[compositor,renderable("input"+type),"ajaxed"]);
if(validator){input.addDelegate(validator);}
return input;
}
Does that make sense?
1) How would I check if an object implements a certain behavior?
Most people don't bother with testing for method existance like this.
If you want to test for methods in order to branch and do different things if its found or not then you are probably doing something evil (this kind of instanceof is usually a code smell in OO code)
If you are just checking if an object implements an interface for error checking then it is not much better then not testing and letting an exception be thrown if the method is not found. I don't know anyone that routinely does this checking but I am sure someone out there is doing it...
2) How would I initialize an object without repeating all the set-up for composited objects?
If you wrap the inner object construction code in a function or class then I think you can avoid most of the repetition and coupling.
3) Is there any performance loss associated with having most of the functions that run in the app go through an apply()?
In my experience, I prefer to avoid dealing with this unless strictly necessary. this is fiddly, breaks inside callbacks (that I use extensively for iteration and async stuff) and it is very easy to forget to set it correctly. I try to use more traditional approaches to composition. For example:
Having each owned object be completely independent, without needing to look at its siblings or owner. This allows me to just call its methods directly and letting it be its own this.
Giving the owned objects a reference to their owner in the form of a property or as a parameter passed to their methods. This allows the composition units to access the owner without depending on having the this correctly set.
Using mixins, flattening the separate composition units in a single level. This has big name clash issues but allows everyone to see each other and share the same "this". Mixins also decouples the code from changes in the composition structure, since different composition divisions will still flatten to the same mixed object.
4) Any good resources?
I don't know, so tell me if you find one :)

Clarification about Javascript objects inserted into DOM?

I am working on a personal project involving some jQuery / native Javascript programming. I am hoping somebody can clarify an issue I'm seeing with my code. I'm confused about the relationship among objects created in Javascript and objects that are part of the DOM.
When using JQuery UI (the tabs feature), my program behaves differently depending on whether I manipulate my object from Javascript directory, or if I first access it from the DOM API, which leads me to believe that the two references are not equal.
For Example:
myObject = $(document.createElement("div")).attr("id", "tabs");
$("body").append(myObject);
Now, I have found that the following example works correctly:
$("#tabs").tabs();
But the following does not:
$(myObject).tabs();
Am I correct in assuming that the object I am retrieving via $("#tabs") is different or works different than the object I have created manually in Javascript (myObject)?
Is there some mechanism that is invoked once you insert an object into the DOM? Should I not be tinkering with it after I insert it into the DOM, and instead re-retrieve it via its id field?
Creating elements with the raw JS methods is no different to any element referenced with jQuery except that those found by expressions like $(...) are wrapped in a jquery object.
Since you're doing this:
myObject = $(document.createElement("div")).attr("id", "tabs");
you already have a jquery object so you should be able to do this:
myObject.tabs();
By doing:
$(myObject).tags();
you're effectively doing this:
$($(document.createElement(...)...);
and I'm not sure what the expected behaviour of that is.
Also bear in mind you can do this (and should favour this way):
var myObject = $("<div></div>").attr("id", "tabs");
The var makes it local in scope (which is what you want 95% of the time) and you can create arbitrary markup with jquery without using the raw JS methods.

Using jQuery's datastore vs. expando properties

I'm developing code using jQuery and need to store data associated with certain DOM elements. There are a bunch of other questions about how to store arbitrary data with an html element, but I'm more interested in why I would pick one option over the other.
Say, for the sake of extremely simplified argument, that I want to store a "lineNumber" property with each row in a table that is "interesting".
Option 1 would be to just set an expando property on each DOM element (I hope I'm using the term 'expando' correctly):
$('.interesting-line').each(function(i) { this.lineNumber = i; });
Option 2 would be to use jQuery's data() function to associate a property with the element:
$('.interesting-line').each(function(i) { $(this).data('lineNumber', i); });
Ignoring any other shortcomings of my sample code, are there strong reasons why you would choose one means of storing properties over the other?
Using $.data will protect you from memory leaks.
In IE, when you assign a javascript object to an expando property on a DOM element, cycles that cross that link are not garbage collected. If your javascript object holds a reference to the dom object, the whole cycle will leak. It's entirely possible to end up with hidden references to DOM objects, due to closures, so you may leak without realizing it.
The jQuery datastore is set up to prevent these cycles from forming. If you use it, you will not leak memory in this way. Your example will not leak because you are putting primitives (strings) on the DOM element. But if you put a more complex object there, you risk leaking.
Use $.data so you won't have to worry.
If you are authoring a plugin you should use $.data. If you need to store the attribute often and rarely need to query the DOM for it then use $.data.
Update 5 years later: jQuery does not query the DOM based on expando properties set, and hasn't done so for a while. So use $.data. There's no reason to pollute the DOM when there is no pragmatic use to do so.
Using $.data doesn't modify the DOM. You should use $.data. If you're creating a plugin then you should store one object in $.data with properties on that object as opposed to storing each of those properties as different key/value pairs in the $.data structure.
Let me rephrase the question: What are the practical differences between the two data binding options available?
Actually there are three options:
$(e).prop('myKey', myValue);
$(e).data('myKey', myValue);
$(e).attr('data-myKey', myValue);
Note: OP’s e.myKey = myValue is practically the same as the .prop() line.
if you need more than strings, use .prop(), i.e. expando properties
if you need DOM/CSS transparency and/or HTML serialization use .attr('data-*')
if you need both you are out of luck
if you only use strings, but need no DOM, read on to weigh pros and cons yourself
what is with .data() → read the last two paragraphs
If you ever want to pass the data around with serialized HTML you need the .attr() solution. I.e. whenever you use things like .innerHTML or .html() or want to construct snippets from strings with data included. The same applies if you want to use CSS selectors like elem[data-myKey]. Disadvantage: you can only store strings.
If you don’t need your data to be visible in the DOM or available to CSS interaction .data() and .prop() might work. Their biggest advantage is: they can hold any Javascript value.
.prop() biggest disadvantage is the possibility of name collision. Only pick names you can be sure will not be used as native property ever. E.g. scope as key is a bad idea, because it exists on some HTML elements...
Now comes .data(). The other answers seem to swear on it, I avoid it. The memory leaks related to .prop() and expando properties in general belong to the past, so that is no advantage any more. But you will be secured against name collisions with HTML properties. That is an advantage. But you get a bunch of disadvantages:
$(e).data('myKey') draws its uninitialized value from the data-myKey attribute if available, runs JSON.parse() on those and sometimes returns that or falls back to the string value of the attribute. Once you set $(e).data('myKey', myValue) you lose the relationship with the data-myKey attribute, which nevertheless lives on with its “old” value, shown in DOM and in CSS interactions. On top, the key name you use is subject to possible name mangling. I.e. if you ever decide to read all key-value via $(e).data() the keys in that object might be different.
Because of this erratic behavior (mixing expando property technology with data-* attributes) and inconsistent get/set design I always avoid .data().—Fortunately that is easy to do with .prop() and .attr() (with data-* keys for compliance).
If you really want to use .data() to avoid name clashes with native properties, my advice: do not mix with data-* attributes, consider them a different thing, and avoid name clashes with those.—Does that make sense? For automatic clash avoidance you have to avoid clashes elsewhere manually. Great design.

Categories

Resources