Roll out your own JavaScript Interfaces
There are times when using a JavaScript library is called for. Building large web applications that use a wide array of utility functions that help aid in developing multi-tiered class systems, advanced UI components, complex event models, and heavy use of DOM scripting helpers. Yep. Those are all great. However, there are other times when you don't need all that. And often what we end up doing is just importing a few of our favorite functions as globals, and work off those. But what ends up happening in this case is that we lose the particular style that these libraries offer. For instance, I'd still like to be able to do something like this without a library.Sample application code
$('foo', 'bar').on('click', function(e) {
$(this).css({
color: 'green',
fontSize: '2em'
}).addClass('active');
});
Starting from scratch
Since we all have a love for the old dollar function introduced by Prototype, we can use that as a base.Original Prototype $ function
function $() {
var elements = [];
for (var i = 0; i < arguments.length; i++) {
var element = arguments[i];
if (typeof element == 'string')
element = document.getElementById(element);
if (arguments.length == 1)
return element;
elements.push(element);
}
return elements;
}
However, instead of treating this as a normal function, we'll transform it into a constructor, then assign instance methods. Then of course to achieve chainability, all we have to do is simply return the instance reference. We'll start off by creating a private interface, then adapt the dollar function to return this private constructor.
Creating the interface
(function() {
// private constructor
function _$(els) {
this.elements = [];
for (var i=0; i<els.length; i++) {
var element = els[i];
if (typeof element == 'string') {
element = document.getElementById(element);
}
this.elements.push(element);
}
return this;
}
_$.prototype = {
each: function(fn) {
for ( var i = 0, len = this.elements.length; i<len; ++i ) {
fn.call(this, this.elements[i]);
}
return this;
},
setStyle: function(prop, val) {
this.each(function(el) {
el.style[prop] = val;
});
return this;
},
addClass: function(className) {
this.each(function(el) {
el.className += ' '+className;
});
return this;
},
on: function(type, fn) {
var listen = function(el) {
if (window.addEventListener) {
el.addEventListener(type, fn, false);
} else if (window.attachEvent) {
el.attachEvent('on'+type, function() {
fn.call(el, window.event);
});
}
};
this.each(function(el) {
listen(el);
});
return this;
},
css: function(o) {
var that = this;
this.each(function(el) {
for (var prop in o) {
console.log(prop);
that.setStyle(prop, o[prop]);
}
});
return this;
}
};
window.$ = function() {
return new _$(arguments);
}
})();
Short and concise! Check out an implementation of this code in action to see how easy it is to start rolling out your own personal interfaces. Cheers.
recent
- Matador: The Obvious MVC Framework for Node
- Sandboxing JavaScript
- Crouching Ender, hidden command
- Ender.js - The open submodule library
- Qwery - The Tiny Selector Engine
- Klass
- Smallest DOMReady code, ever.
- $script.js - Another JavaScript loader
- About that slowness on Twitter...
- Autocomplete Fuzzy Matching
- JavaScript Cache Provider
- JavaScript Animate
- Asynchronous method queue chaining in JavaScript
- Something changed
- Unofficial Twitter Widget Documentation
i am dustin diaz

