The Composite Pattern

The Composite pattern describes a group of objects that can be treated in the same way a single instance of an object may be.

This allows us to treat both individual objects and compositions in a uniform manner, meaning that the same behavior will be applied regardless of whether we’re working with one item or a thousand.

In jQuery, when we’re applying methods to an element or collection of elements, we can treat both sets in a uniform manner, as both selections return a jQuery object.

This is demonstrated by the code sample using the jQuery selector below. Here, it’s possible to add an active class to both selections for a single element (e.g., an element with a unique ID) or a group of elements with the same tag name or class, without additional effort:

// Single elements
$( "#singleItem" ).addClass( "active" ); 
$( "#container" ).addClass( "active" ); 

// Collections of elements
$( "div" ).addClass( "active" ); 
$( ".item" ).addClass( "active" ); 
$( "input" ).addClass( "active" );

The jQuery addClass() implementation could either directly use native for loops (or jQuery’s jQuery.each()/jQuery.fn.each()) to iterate through a collection in order to apply the method to both single items or groups. Looking through the source, we can see this is indeed the case:

    addClass: function( value ) {
    var classNames, i, l, elem,
      setClass, c, cl;

    if ( jQuery.isFunction( value ) ) {
      return this.each(function( j ) {
        jQuery( this ).addClass( value.call(this, j, this.className) );
      });
    }

    if ( value && typeof value === "string" ) {
      classNames = value.split( rspace );

      for ( i = 0, l = this.length; i < l; i++ ) {
        elem = this[ i ];

        if ( elem.nodeType === 1 ) {
          if ( !elem.className && classNames.length === 1 ) {
            elem.className = value;

          } else {
            setClass = " " + elem.className + " ";

            for ( c = 0, cl = classNames.length; c < cl; c++ ) {
              if ( !~setClass.indexOf( " " + classNames[ c ] + " " ) ) {
                setClass += classNames[ c ] + " ";
              }
            }
            elem.className = jQuery.trim( setClass );
          }
        }
      }
    }

    return this;
  }

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.