It should now be universally accepted that extending the DOM directly (via Element.prototype, Node.prototype etc.) is a bad idea. To combat the inherent problems with doing this, quite a few libraries (jQuery, BBC Glow, etc.) employ the “wrapper” technique which involves taking a bunch of DOM elements and stuffing them into an array-like object that inherits from a safely-extendible prototype.

If you want to have a go at creating your own jQuery-like DOM library, here’s something to get you started:

window.myWrapper = (function(){
 
    // "cache" useful methods, so they don't
    // have to be resolved every time they're used
    var push = Array.prototype.push,
        slice = Array.prototype.slice,
        toString = Object.prototype.toString,
 
        isArray = function(o) {
            toString.call(o) === '[object Array]';
        },
 
        toArray = (function(){
 
            try {
 
                // Return a basic slice() if the environment
                // is okay with converting NodeLists to
                // arrays using slice()
 
                slice.call(document.childNodes);
 
                return function(arrayLike) {
                    return slice.call(arrayLike);
                };
 
            } catch(e) {}
 
            // Otherwise return the slower approach
 
            return function(arrayLike) {
 
                var ret = [], i = -1, len = arrayLike.length;
 
                while (++i < len) {
                    ret[i] = arrayLike[i];
                }
 
                return ret;
 
            };
 
        })();
 
    function NodeList(elems) {
 
        this.length = 0;
 
        push.apply(
            this,
            elems.nodeType ?
                [elems] // Single node
                : isArray(elems) ?
                    elems // Real array
                    : toArray(elems) // NodeList/Array-like-object
        );
 
    }
 
    function myWrapper(elems) {
        // Instantiate and return new NodeList
        return new NodeList(elems);
    }
 
    myWrapper.NodeList = NodeList;
 
    NodeList.prototype = {
 
        each: function(fn) {
 
            for (var i = -1, l = this.length; ++i < l;) {
                fn.call(this[i], this[i], i, l, this);
            }
 
            return this;
 
        }
 
    };
 
    return myWrapper;
 
})();

There’s no selector engine, but it’s easy enough to slot one in:

function myWrapper(elems) {
    // E.g. using Sizzle as the selector engine
    return new NodeList( typeof elems === 'string' ? Sizzle(elems) : elems );
}

Example of usage:

myWrapper(document.getElementsByTagName('div')).each(function(){
    alert(this.id);
});
// Etc.

Extending NodeList:

myWrapper.NodeList.prototype.applyCSS = (function(){
 
    var hasOwn = Object.prototype.hasOwnProperty;
 
    return function(props) {
 
        for (var i = -1, l = this.length; ++i < l;) {
            for (var p in props) {
                if (hasOwn.call(props, p)) {
                    this[i].style[p] = props[p];
                }
            }
        }
 
        return this;
 
    };
 
}());
 
// Usage:
myWrapper(document.body).applyCSS({
    background: 'red',
    color: 'yellow'
});

Thanks for reading! Please share your thoughts with me on Twitter. Have a great day!