My JavaScript book is out! Don't miss the opportunity to upgrade your beginner or average dev skills.
Showing posts with label unobtrusive. Show all posts
Showing posts with label unobtrusive. Show all posts

Wednesday, July 16, 2008

JavaScript Relator Object, aka unobtrusive informations

Have you never though about add, modify, or remove a generic information from a variable, and without changing variable itself?
This is all about what my last simple creation does.



Relator Object Concept


The main purpose for this object is to associate every kind of information, value, or function, into a generic variable, whatever it is, and without modifying its native state.
To obtain this result, I have used a 1:1 relationship between a stack that will contain every stored variable, and another one that will contain related objects.

Stack = [1, 2, 3];
RelatedObject = [{}, {}, {}];

// add a property
RelatedObject[Stack.indexOf(2)].description = "Number 2";

// remove a property
Stack.splice(0, 1);
RelatedObject.splice(0, 1);

// situation
Stack = [2, 3];
RelatedObject = [{description:"Number 2"}, {}];

Using above strategy we obtain 2 benefits:

  1. The Stack does not cause memory leaks

  2. both Stack and RelatedObject are alway as small, and fast, as possible





Related Object Code



var Relator = function(Array, Object){
// (c) Andrea Giammarchi - Mit Style License
if(!Array.indexOf)
Array.indexOf = function(value){
for(var i = 0, length = Array.length; i < length; i++)
if(Array[i] === value)
return i;
return -1
};
return {
get:function(value){
return Object[Array.indexOf(value)]
},
set:function(value){
var i = Array.indexOf(value);
return ~i ? Object[i] : Object[Array.push(value) - 1] = {}
},
del:function(value){
var i = Array.indexOf(value);
if(~i){
Array.splice(i, 1);
Object.splice(i, 1);
};
return this
}
}
}([], []);

I hope, and I suppose, the 3 methods API talks by itself.
set is used to create a relation, if this does not exists, returning associated object.
get is used only to get a relation or undefined, if this does not exist.
Finally, del, is used to delete the relation, reducing the Array size, and deleting related Object.



Some Example


Try to imagine that we are using a library, but we would be able to add any sort of info about them, or implement something for our purpose.

var jQueryMore = Relator.set(jQuery);
jQueryMore.details = "jQuery library";
jQueryMore.isCompatible = function(){
return window.$ === jQuery;
};

// in every other piece of code ...
if(Relator.get(jQuery).isCompatible())
alert("I am using the " + Relator.get(jQuery).details);
// I am using the jQuery library




Relator Performances


IE a part, since it still does not implement natively the old indexOf Array method, performance to set, access, modify, or delete related informations, are probably the best possible, closes to zero value.
We can test by ourself using 10000 stored relations, and accessing to the last one.

for(var i = 0; i < 10000; i++)
Relator.set("number " + i).description = "The " + i + " number";

time = new Date;
description = Relator.get("number " + 9999).description;
time = new Date - time;
alert([description, time]);




Conclusion


The Relator object is based on our own variables, and it is not a container, a register, or a IOC emulator, at all.
At the same time, to be able to relate an object with a generic variable (undefined included, as example), it needs to store them in the Stack.
This could be a problem for memory leaks, but only if we forget to use the del method, to remove the assigned, and protected, relation between our global scope whatever, and the internal object dedicated relation.
Applications? In my mind, this object could make a lot of stuff simpler than ever, specially in those case where we would like, for example, monitor variables, singleton or global instances, during our script life :)

Thursday, June 19, 2008

Has this constructor been prototyped?

This is a quick post about libraries that uses native constructor in an obtrusive way.
Using a Function prototype, that sounds like a non-sense, it is possible to know if a constructor has some property, or method, defined in its prototype.

Function.prototype.prototyped = function(){
for(var i in new this)
return true;
return false;
};


Some test example?

alert(Array.prototyped()); // false

Object.prototype.each = function(){};
alert(Array.prototyped()); // true

delete Object.prototype.each;
alert(Array.prototyped()); // false

Array.prototype.each = function(){};
alert(Array.prototyped()); // true
alert(Object.prototyped()); // false


Update
Has Kangas spotted, there is no reason to create a new instance.
We could loop directly the prototype object.
But what's up if we have injected privileged methods in the constructor?

Array = function(Array){
var prototype = Array.prototype;
return function(){
arguments = prototype.slice.call(arguments, 0);
arguments.each = function(){
prototype.forEach.apply(this, arguments);
};
return arguments;
};
}(Array);

var a = new Array(1, 2, 3);
a.each(function(value){
alert(value)
});

for(i in Array.prototype)
alert(i); // nothing

Above example is the reason I chose to create an instance ... but hey, why on heart someone should wrap a native constructor? :P