Decorators with jQuery

As with other patterns we’ve covered, there are also examples of the Decorator pattern that can be implemented with jQuery. jQuery.extend() allows us to extend (or merge) two or more objects (and their properties) together into a single object either at run-time or dynamically at a later point.

In this scenario, a target object can be decorated with new functionality without necessarily breaking or overriding existing methods in the source/superclass object (although this can be done).

In the following example, we define three objects: defaults, options, and settings. The aim of the task is to decorate the defaults object with additional functionality found in optionssettings. We must first leave defaults in an untouched state where we don’t lose the ability to access the properties or functions found in it at a later point; then, gain the ability to use the decorated properties and functions found in options:

var decoratorApp = decoratorApp || {};

// define the objects we're going to use
decoratorApp = {

    defaults: {
        validate: false,
        limit: 5,
        name: "foo",
        welcome: function () {
            console.log( "welcome!" );
        }
    },

    options: {
        validate: true,
        name: "bar",
        helloWorld: function () {
            console.log( "hello world" );
        }
    },

    settings: {},

    printObj: function ( obj ) {
        var arr = [],
            next;
        $.each( obj, function ( key, val ) {
            next = key + ": ";
            next += $.isPlainObject(val) ? printObj( val ) : val;
            arr.push( next );
        } );

        return "{ " + arr.join(", ") + " }";
    }

};

// merge defaults and options, without modifying defaults explicitly
decoratorApp.settings = $.extend({}, decoratorApp.defaults, decoratorApp.options);

// what we have done here is decorated defaults in a way that provides 
// access to the properties and functionality it has to offer (as well as 
// that of the decorator "options"). defaults itself is left unchanged

$("#log")
    .append( decoratorApp.printObj(decoratorApp.settings) +  
          + decoratorApp.printObj(decoratorApp.options) +
          + decoratorApp.printObj(decoratorApp.defaults));

// settings -- { validate: true, limit: 5, name: bar, 
welcome: function (){ console.log( "welcome!" ); }, 
// helloWorld: function (){ console.log("hello!"); } }
// options -- { validate: true, name: bar, 
helloWorld: function (){ console.log("hello!"); } }
// defaults -- { validate: false, limit: 5, name: foo, 
welcome: function (){ console.log("welcome!"); } }

Get Learning JavaScript Design Patterns now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.