I have written myself a little JavaScript library for personal use, and anyone who'd like to use it for some reason. The reason why I decided to create my own library instead of using the already existing ones is that I have found out in the course of practice that I only use a very small amount of the functionality modern libraries offer. So I figured instead of loading big libraries and not using them, why not create a small one that fits my needs perfectly. However I am nowhere near a JavaScript expert and I have no clue whether what I have written is efficient at all. This is why I would like to ask you to review my little work of art and suggest any improvements.
Here's the very base of the library:
function MF(selector){
this.nodes = new Array();
if(!selector) return;
if(!(this instanceof MF)) return new MF(selector);
if(selector instanceof MF) return selector;
if (typeof selector === 'string') {
switch (selector.substring(0, 1)) {
case '#':
selector = document.getElementById(selector.substring(1));
if(selector){
this.nodes.push(selector);
}
break;
case '.':
this.nodes = Array.prototype.slice.call(document.getElementsByClassName(selector.substring(1).replace(/\./g, ' ')), 0);;
break;
default :
this.nodes = Array.prototype.slice.call(document.getElementsByTagName(selector), 0);
break;
}
} else if (selector.nodeType === 1 || selector === document || selector === window) {
this.nodes.push(selector);
} else if (selector instanceof HTMLCollection || selector instanceof NodeList) {
this.nodes = Array.prototype.slice.call(selector, 0);
}
};
MF.function = function(fname, fbody){
Object.defineProperty(MF.prototype, fname, {
value: function() {
var args = Array.prototype.slice.call(arguments, 0), rv;
MF.foreach(this.nodes, function(k,v){
rv = fbody.apply(v, args);
if(rv !== undefined) return false;
});
return this.nodes.length ? rv === undefined ? this : rv : undefined;
}
});
};
MF.foreach({
html: function(html) {
if(html === undefined){
return this.innerHTML;
}else{
this.innerHTML = '';
MF(this).append(html);
}
},
append: function(item) {
if(item instanceof MF){
item.invoke(function($this){ $this.appendChild(this); }, this);
}else{
(item instanceof Node) ? this.appendChild(item) : this.insertAdjacentHTML('beforeend',item.toString());
};
},
...
}, MF.function);
Here is an example use:
HTML
<div id='foo'></div>
<div class='bar'></div>
JavaScript
MF('#foo').html('bar');
MF('.bar').html('foo');
You will find it pretty similar to jQuery. So basically by using MF(selector)
I can select an element by either id, class, tag or provide a DOM element or list as a selector. The reason why I chose this over .querySelectorAll()
because I believe this to be faster as I remember seeing a benchmark that proved .querySelectorAll()
to be pretty slow. There is also the .find()
method in the prototype that uses .querySelectorAll()
in order for all CSS selectors to be available. The way I extend the prototype is with the method MF.function
. As you see a single object may hold a number of nodes, so if a method is called with a syntax like so
MF('div').addCLass('class');
And there are more than one div
s, then method addClass
needs to be called on each one of them. That's what MF.function
takes care of, and also returns the object if the method did not return a value, for chaining to be available.
I'd love to hear some advise on how to improve this little project. Even though it is not finished yet, here is the full code I have at the moment.
I don't include support for those million-years-old browsers. My way of discouraging their use!