Pakal De Bonchamp
Pakal De Bonchamp

Reputation: 73

Make a javascript "function object" inherit from another

In Javascript, it's possible to have some kind of inheritance, by using function contructors and their "prototype" attribute (i.e the "parent of future instances"), or more recently Object.create(), to get new objects.

However recently I needed to "override" the Jquery object ("$") for one of my projects, that is to say, provide a similar function, which also has all the fn/extend/... [inherited] attributes of the original "jQuery" factory function.

The goal was to have a "$()" function which always received "window.parent" as the second parameter by default, so that the whole program modified the parent frame and not the iframe in which the program was loaded.

Typically I expected to be able to do something like this:

var oldJQ = $;
$ = function (selector) {
    return oldJQ(selector, window.parent);
}
$.__proto__ = oldJQ .__proto__;

$.extend({...});  // must work

Despite numerous attempts, I couldn't get it to work, I always got simple objects instead of real functions when using the "new" keyword, or the inheritance didn't work. I found alternative ways (for example, by copy-pasting all attributes from $ into my new function object), but it seems to me like a horrible way of doing stuffs.

Is there any way to have a new function object which has, as a parent/prototype, the original $ object ?

Upvotes: 0

Views: 352

Answers (1)

slebetman
slebetman

Reputation: 113896

While functions are objects in javascript, they aren't regular objects. Specifically, they're objects for which inheritance is broken. Functions are not the only such objects in the language, DOM elements are similarly handicapped. That's one reason jQuery is implemented as wrapper around DOM rather than extending the DOM's features via inheritance.

Fortunately, while OOP doesn't work in this case, we can take inspiration from jQuery itself and use FP to do what we need. In other words, while you can't inherit functions, you can wrap it in another function.

For example, if you need a special console.log function for your app that sends logs back to your server you can override it by redefining it:

var log_orig = console.log;
console.log = function () {
    ajaxlog([].slice.call(arguments,0).map(function(x){
        return JSON.parse(x);
    }).join(',');
    log_orig.apply(console,arguments);
}

Or if you want a special version of $ that does something extra:

function $$ () {
    /*
     * do extra stuff
     */
    return $.apply(null,arguments);
}

Or if you want to override $ instead if wrapping:

var old$ = $;
function $ () {
    /*
     * do extra stuff
     */
    return old$.apply(null,arguments);
}

Upvotes: 2

Related Questions