From time to time I see people blogging about their most favorite or useful functions. Here’s a little function I wrote called absorb(). Its purpose is quite simple, to have one object “absorb” another, i.e., an object receives all of the properties and methods of another object. The difference from other similar functions is that this one allows you to specify not to overwrite existing properties/methods of the same name. Here’s the function:

function absorb(destination /*:Object*/, source /*:Object*/, dontOverwrite /*:Boolean*/) {
    for (var key in source) {
        if (!dontOverwrite || typeof destination[key] == "undefined"){
            destination[key] = source[key];
        }
    }
}

I’ve found this function useful in many cases, but the most useful is when implementing methods for native JavaScript objects that may exist only in certain browsers. Reading this post over at Dustin’s reminded me to post this. In the post, he talks about checking for the existence of the foreEach() method on Array.prototype before defining his own version. This is a perfect example of how to use absorb():

absorb(Array.prototype, {
    forEach: function () { ... }
}, true);

By setting the last argument as true, absorb() won’t overwrite any existing implementation of forEach() (you can omit the last argument if you want it to overwrite existing methods). You can think of this function as a sort of smart extension mechanism: you can use it to copy properties/methods to an object’s prototype for easy subclassing or you can add properties/methods to an already instantiated object that doesn’t support inheritance (like DOM elements in Internet Explorer). There are plenty of uses for absorb(), have fun!

Update: After seeing the comments from JCurtis and Dustin, both of whom pointed out that having a variable named dontOverwrite is a little confusing, I’ve changed the function from the above to this:

function absorb(destination /*:Object*/, source /*:Object*/, overwrite /*:Boolean*/) {
    for (var key in source) {
        if (overwrite || typeof destination[key] == "undefined"){
            destination[key] = source[key];
        }
    }
}

This does change the behavior so that the default is to not overwrite any existing properties/methods of the same name. Meaning that the previous example should now be:

absorb(Array.prototype, {
    forEach: function () { ... }
});

This is really the way it should work – you should never purposely overwrite existing methods. Thanks guys for the suggestions.

Disclaimer: Any viewpoints and opinions expressed in this article are those of Nicholas C. Zakas and do not, in any way, reflect those of my employer, my colleagues, Wrox Publishing, O'Reilly Publishing, or anyone else. I speak only for myself, not for them.

Both comments and pings are currently closed.