2

Let's say I have a function like the one below that creates a very simple micro-library:

var microLib = function(selector) {
    var el;
    var selectorEngine = function(selector)
    {
        var selector_value = selector.slice(1);
        return document.getElementById(selector_value);
    };

    el = selectorEngine(selector);

    Element.prototype.func_1 = function(){
        return 'first';
    };

    Element.prototype.func_2 = function(){
        return 'second';
    };

    return el;
};
window._$ = microLib;

This script will allow me to write code like this:

var elem = _$("#div_with_id");   //some element on my web page
console.log(elem.func_2());      //outputs 'second' in the console 

So now, I'm looking for a way to extend _$ in a supplementary piece of code to add additional Element.prototype methods, which will allow me to write:

console.log(elem.func_3());    //to output 'third' in the console

The reason I need to do this is because this extension needs to take place in another JavaScript file, otherwise I would I have just added another method and be done with it.

How can I do this?

9
  • 1
    That's very unclear, very bad practice (Extending Element without a really excellent reason is terrible), and very... useless?? Commented Jul 9, 2015 at 22:25
  • Since you are already doing this horrendous practice of modifying Element.prototype, just add func_3 in the same way. I don't understand where the problem is. Commented Jul 9, 2015 at 22:31
  • Since you are creating your own micro library, then why exactly do you need to modify Element.prototype? Create methods on the prototype of the function such that these methods operate on the selected elements. That way you can implement _$(#div_with_id).func_3() vs. elem.func_3(). Commented Jul 9, 2015 at 22:40
  • 1
    Exactly, extend _$ and not Element. Commented Jul 9, 2015 at 22:47
  • 1
    See a more detailed example in my answer. Commented Jul 9, 2015 at 23:12

2 Answers 2

2

Here's an example of the approach that I am suggesting: http://jsfiddle.net/rbxssmx8/.

JS:

var toArray = Function.prototype.call.bind(Array.prototype.slice);
var qAll = document.querySelectorAll.bind(document);

var _$ = (function() {
    function dom(selector) {
        if(!(this instanceof dom)) {
            return new dom(selector);
        }

        this.elements = toArray(qAll(selector));
    }    

    dom.prototype.iterate = function(func) {
        this.elements.forEach(func);
        return this;
    };

    dom.prototype.addClass = function() {
        var klasses = arguments;
        return this.iterate(function(element) {
            element.classList.add.apply(element.classList, klasses);
        });
    };

    dom.extend = function(name, func) {
        this.prototype[name] = func;    
    };

    dom.ready = function(func) {
        document.addEventListener("DOMContentLoaded", func);    
    };

    return dom;
})();

_$.extend("removeClass", function() {
    var klasses = arguments;
    return this.iterate(function(element) {
        element.classList.remove.apply(element.classList, klasses);    
    });
});

_$("div").addClass("gray");
var $el = _$("div:last-of-type");
$el.removeClass("gray");
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks. Used some parts of it to fix my code. Cheers.
1

So I read this post on What's wrong with extending the DOM and the alternative suggested by the author was to use Object Wrappers. A quick search on that led me to this post on SO: Using object wrappers to extend the JavaScripts DOM?

Coupled with some insight from @DRD's answer, I updated my code:

(function() {

    var microLib = function (selector){
        return new Dom(selector);
    };

    function Dom(selector)
    {
        var selector_value = selector.slice(1);
        this.element = document.getElementById(selector_value);
    }

    Dom.prototype.func_1 = function(){
        return 'first';
    };

    Dom.prototype.func_2 = function(){
        return 'second';
    };

    microLib.extend = function(name, func){
        Dom.prototype[name] = func;
    };

    window._$ = microLib;

})();

And then whenever you want to extend and add another function, do this afterwards:

_$.extend('func_3', function(){ //this is inline with my earlier question
     return 'third';
});

Works like a charm! And definitely the safer option compared to extending Element.prototype.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.