Chapter 3. Objects

With the combination of prototypal inheritance, dynamic object extension, and closures, JavaScript has one of the most flexible and expressive object systems available in any popular programing language.

In JavaScript, all types of functions, arrays, key/value pairs, and data structures in general are really objects. Even primitive types get the object treatment when you refer to them with the property access notations. They get automatically wrapped with an object so that you can call their prototype methods. For example:

'tonya@example.com'.split('@')[1]; // => example.com

Caution

Primitive types behave like objects when you use the property access notations, but you can’t assign new properties to them. Primitives get wrapped with an object temporarily, and then that object is immediately thrown away. Any attempt to assign values to properties will seem to succeed, but subsequent attempts to access that new property will fail.

JavaScript’s object system is so powerful and expressive that most of the complexity in common OO patterns melts away when you reproduce them in JavaScript. You simply don’t need all of the common cruft to accomplish the stated goals. For instance, because JavaScript is classless, and it’s possible to create an object on demand at the precise moment it’s needed (lazy instantiation), the singleton is reduced to an object literal:

var highlander = {
    name: 'McLeod',
    catchphrase: 'There can be only one.'
  };

As you continue through this chapter, you’ll see that much of the overhead associated with several other GoF design patterns melts away when you understand how to take advantage of JavaScript’s native object capabilities.

You may be aware that JavaScript is not a classical OO language. It’s a prototypal language. However, most JavaScript training materials ignore some of the implications of that paradigm shift. It’s time to get a firmer handle on exactly what prototypal means and how you can take advantage of it to write better, faster, more readable, and more efficient code. It might help to get a better sense of the shortcomings of classical inheritance first.

Classical Inheritance Is Obsolete

Those who are unaware they are walking in darkness will never seek the light.

Bruce Lee

In Design Patterns: Elements of Reusable Object Oriented Software, the Gang of Four opened the book with two foundational principles of object-oriented design:

  1. Program to an interface, not an implementation.

  2. Favor object composition over class inheritance.

In a sense, the second principle could follow from the first, because inheritance exposes the parent class to all child classes. The child classes are all programming to an implementation, not an interface. Classical inheritance breaks the principle of encapsulation and tightly couples the child class to its ancestors.

Think of it this way: classical inheritance is like Ikea furniture. You have a bunch of pieces that are designed to fit together in a very specific way. If everything goes exactly according to plan, chances are high that you’ll come out with a usable piece of furniture; but if anything at all goes wrong or deviates from the preplanned specification, there is little room for adjustment or flexibility. Here’s where the analogy (and the furniture and the software) breaks down: the design is in a constant state of change.

Composition is more like Lego blocks. The various pieces aren’t designed to fit with any specific piece. Instead, they are all designed to fit together with any other piece, with few exceptions.

When you design for classical inheritance, you design a child class to inherit from a specific parent class. The specific parent class name is usually hardcoded right in the child class, with no mechanism to override it. Right from the start, you’re boxing yourself in—limiting the ways that you can reuse your code without rethinking its design at a fundamental level.

When you design for composition, the sky is the limit. As long as you can successfully avoid colliding with properties from other source objects, objects can be composed and reused virtually any way you see fit. Once you get the hang of it, composition affords a tremendous amount of freedom compared to classical inheritance. For people who have been immersed in classical inheritance for years and learn how to take real advantage of composition (specifically using prototypal techniques), it is like walking out of a dark tunnel into the light and seeing a whole new world of possibilities open up for you.

Back to Design Patterns. Why is the seminal work on object-oriented design so distinctly anti-inheritance? Because inheritance causes several problems:

Tight coupling

Inheritance is the tightest coupling available in OO design. Descendant classes have an intimate knowledge of their ancestor classes.

Inflexible hierarchies

Single-parent hierarchies are rarely capable of describing all possible use cases. Eventually, all hierarchies are “wrong” for new uses—a problem that necessitates code duplication.

Multiple inheritance is complicated

It’s often desirable to inherit from more than one parent. That process is inordinately complex, and its implementation is inconsistent with the process for single inheritance, which makes it harder to read and understand.

Brittle architecture

With tight coupling, it’s often difficult to refactor a class with the “wrong” design, because much existing functionality depends on the existing design.

The gorilla/banana problem

There are often parts of the parent that you don’t want to inherit. Subclassing allows you to override properties from the parent, but it doesn’t allow you to select which properties you want to inherit.

These problems are summed up nicely by Joe Armstrong in Coders at Work by Peter Siebel:

The problem with object-oriented languages is they’ve got all this implicit environment that they carry around with them. You wanted a banana but what you got was a gorilla holding the banana and the entire jungle.

Inheritance works beautifully for a short time, but eventually the app architecture becomes arthritic. When you’ve built up your entire app on a foundation of classical inheritance, the dependencies on ancestors run so deep that even reusing or changing trivial amounts of code can turn into a gigantic refactor. Deep inheritance trees are brittle, inflexible, and difficult to extend.

More often than not, what you wind up with in a mature classical OO application is a range of possible ancestors to inherit from, all with slightly different but often similar configurations. Figuring out which to use is not straightforward, and you soon have a haphazard collection of similar objects with unexpectedly divergent properties. Around this time, people start throwing around the word “rewrite” as if it’s an easier undertaking than refactoring the current mess.

Many of the patterns in the GoF book were designed specifically to address these well-known problems. In many ways, the book itself can be read as a critique of the shortcomings of most classical OO languages, along with the accompanying lengthy workarounds. In short, patterns point out deficiencies in the language. You can reproduce all of the GoF patterns in JavaScript, but before you start using them as blueprints for your JavaScript code, you’ll want to get a good handle on JavaScript’s prototypal and functional capabilities.

For a long time, many people were confused about whether JavaScript is truly object-oriented, because they felt it lacked features from other OO languages. Setting aside the fact that JavaScript handles classical inheritance with less code than most class-based languages, coming to JavaScript and asking how to do classical inheritance is like picking up a touch-screen mobile phone and asking where the rotary dial is. Of course, people will be amused when the next thing out of your mouth is, “If it doesn’t have a rotary dial, it’s not a telephone!”

JavaScript can do most of the OO things you’re accustomed to in other languages, such as inheritance, data privacy, and polymorphism. However, JavaScript has many native capabilities that make some classical OO features and patterns obsolete. It’s better to stop asking, “How do I do classical inheritance in JavaScript?” and start asking, “What cool new things does JavaScript enable me to do?”

Warning

I wish I could tell you that you’ll never have to deal with classical inheritance in JavaScript. Unfortunately, because classical inheritance is easy to mimic in JavaScript, and many people come from class-based programming backgrounds, there are several popular libraries that feature classical inheritance prominently, including Backbone.js, which you’ll have a chance to explore soon. When you do encounter situations in which you’re forced to subclass by other programmers, keep in mind that inheritance hierarchies should be kept as small as possible. Avoid subclassing subclasses, remember that you can mix and match different code reuse styles, and things will go more smoothly.

Fluent-Style JavaScript

I have not invented a “new style,” composite, modified, or otherwise that is set within distinct form as apart from “this” method or “that” method. On the contrary, I hope to free my followers from clinging to styles, patterns, or molds.

...The extraordinary part of it lies in its simplicity.

Bruce Lee

Programmers with a background in other languages are like immigrants to JavaScript. They often code with an accent—preconceived notions about how to solve problems. For example, programmers with a background in classical OO tend to have a hard time letting constructors go. Using constructor functions is a clear and strong accent, because they are completely unnecessary in JavaScript. They are a waste of time and energy.

Unfortunately, most JavaScript learning materials will teach you that you build objects using constructor functions.

There are serious limitations to this way of doing things. The first is that you must always call a constructor using the new keyword. Failing to do so will pass the global object in as this. Your properties and methods will clobber the global namespace. If you instantiate more than one object, they will not be instance safe. In strict mode, the situation when you forget new is a little different: this is useless, and trying to assign properties to it will throw an error.

There’s a simple workaround that requires a boilerplate check inside every constructor function, but since any function can return an object in JavaScript, you end up using new sometimes, but not all the time. A convention has sprung up in JavaScript to help you remember when to use new and when not to. Constructor functions always begin with a capital letter. If you’re calling a function that begins with a capital letter, use new. Unfortunately, lots of library developers uppercase the first letter of their library namespace, regardless of whether or not it’s a constructor function, so even that solution is less than ideal. And that’s not even the real problem.

The real problem is that using constructors will almost always get you stuck thinking in classical OO mode. The constructor becomes analogous to a class. You might start to think, “I want to subclass x...” and that’s where you get into trouble. You’re ignoring two of the best features of JavaScript: dynamic object extension (you can add properties to any object in JavaScript after instantiation) and prototypal inheritance. The two combined are a much more powerful and flexible way to reuse code than classical inheritance.

Programmers who learned JavaScript as a first language are far less likely to be attached to classical OO and inheritance, because it’s harder to implement in JavaScript than the simpler, native alternatives. You can learn a lot about JavaScript by reading the code of experienced JavaScript natives who have not been influenced by classical inheritance.

Most languages have many different accents and grammars. In fact, almost all disciplines spin off into different schools of thought. Martial arts has kickboxing, jui jitsu, boxing, karate, kung fu, and so on. Each emphasizes different philosophies, mechanics, and core techniques. In his famous book, The Tao of Jeet Kun Do, Bruce Lee advised that you develop your own style. Study and take in all the good things about different styles, pick what you like, and discard the rest to create your own unique style. It’s good advice that lies at the heart of mixed martial arts—a discipline that combines the best features of several fighting styles.

The same is true with programming languages. JavaScript itself is a fusion of the best ideas from Scheme (lambda), Self (prototypal inheritance), and Java (syntax).

To coin a phrase, fluent style simply discards inefficient constructs and takes advantage of JavaScript’s strengths and efficiencies:

Lambdas and closures

These are a language unto themselves. Lambda expressions are simple, elegant, and powerful. Literally anything that can be expressed as a computable algorithm can be expressed through lambdas. Lambdas are an essential ingredient of functional programming.

Object-literal notation

This is the fastest route to a working object instance from scratch. Also take advantage of its sibling, array literal notation.

Dynamic object extension

This allows you to easily use mixins, composition, and aggregation for code reuse, even after object instantiation. Subclassing requires a lot of extra typing and gains you nothing. It makes your code brittle and inflexible.

Prototypes

These allow you to clone instances of existing objects to create new ones and share generic methods on a delegate object.

Factories

These are a more flexible and less verbose alternative to constructor functions in JavaScript. You don’t need constructors to create new objects. Any function in JavaScript can return a new object, and with less code than a constructor requires. Unlike constructors, factories hide instantiation details from the caller, and there’s no need to use the awkward and superfluous new keyword when invoking a factory. Factories make it easy to combine any of the above techniques, and even change implementations at runtime without changing the way that objects are instantiated from outside the factory.

Fluent APIs (not to be confused with fluent-style JavaScript)

A fluent API is an interface that reads a bit like natural language. Fluent APIs are usually chainable but don’t need to be chained to be fluent. The defining characteristic is that each method returns an object that has additional methods on it that make sense as a next step. In this way, methods can be strung together in short sentences, each method acting on the return value of the last. jQuery and Jasmine are examples of popular fluent APIs in JavaScript.

Some of the techniques used in fluent-style JavaScript were popularized by the Prototype and jQuery libraries, but fluent style wasn’t invented by anybody in particular. There isn’t anything new or unique about it that hasn’t been said a thousand times before. It’s simply the natural evolution of a language with this particular blend of features at its core. It is not a style in itself so much as the shedding of unnecessary styles and techniques that are often habits left over from other languages.

Even giving “fluent style” a name seems a bit silly. It’s necessary only to distinguish it from the cumbersome styles taught in most JavaScript books and tutorials. In short, fluent style isn’t really a particular formal style—it’s just what fluent JavaScripters do.

As time marches on, it’s natural to assume that fluent-style JavaScript will and should evolve beyond this definition as new efficiencies are discovered and popularized and new features are added to the language.

Prototypes

A prototype is an object intended to model other objects after. It is similar to a class in that you can use it to construct any number of object instances, but different in the sense that it is an object itself. There are two ways that prototypes can be used: you can delegate access to a single, shared prototype object (called a delegate), or you can make clones of the prototype.

Delegate Prototypes

In JavaScript, objects have an internal reference to a delegate prototype. When an object is queried for a property or method, the JavaScript engine first checks the object. If the key doesn’t exist on that object, it checks the delegate prototype, and so on up the prototype chain. The prototype chain typically ends at the Object prototype.

When you create an object literal, it automatically attaches the Object prototype. Alternatively, you can specify a prototype to set when you create an object via the Object.create() method. Object.create() was added with ES5, so you may need to polyfill it. Here’s the Object.create() polyfill from the Mozilla Developer Network documentation:

if (!Object.create) {
  Object.create = function (o) {
    if (arguments.length > 1) {
      throw new Error('Object.create implementation'
      + ' only accepts the first parameter.');
    }
    function F() {}
    F.prototype = o;
    return new F();
  };
}

When you invoke a constructor with the new keyword, the object referenced by the constructor’s prototype property gets set as the delegate for the newly created object. As you can see, this Object.create() polyfill is simply a shortcut that creates a new constructor function, sets the object you pass in as the constructor’s prototype property, and then returns a new object with that prototype. Here’s how you use it:

var switchProto = {
    isOn: function isOn() {
      return this.state;
    },

    toggle: function toggle() {
      this.state = !this.state;
      return this;
    },

    state: false
  },
  switch1 = Object.create(switchProto),
  switch2 = Object.create(switchProto);

test('Object.create', function () {
  ok(switch1.toggle().isOn(),
    '.toggle() works.'
  );

  ok(!switch2.isOn(),
    'instance safe.'
  );
});

Simply pass any object into Object.create(), and it will be be set as the delegate prototype for the newly created object. As you can see, the delegate prototype has some special behavior.

Notice that state is on the prototype, but changing state on switch1 did not change state on switch2. Properties on the prototype act like defaults. When you set them on the instance, the instance value overrides the value for that instance, only.

It’s important to note though that if you mutate an object or array property on the prototype, that mutation will be shared on the prototype. If you replace the whole property, the change is reflected only on that instance:

var switchProto = {
    isOn: function isOn() {
      return this.state;
    },

    toggle: function toggle() {
      this.state = !this.state;
      return this;
    },

    meta: {
      name: 'Light switch'
    },

    state: false
  },
  switch1 = Object.create(switchProto),
  switch2 = Object.create(switchProto);

test('Prototype mutations.', function () {
  switch2.meta.name = 'Breaker switch';

  equal(switch1.meta.name, 'Breaker switch',
    'Object and array mutations are shared.'
  );

  switch2.meta = { name: 'Power switch' };

  equal(switch1.meta.name, 'Breaker switch',
    'Property replacement is instance-specific.'
  );
});

In the code, switchProto has a property called meta. When you change a subproperty of meta, it mutates the object attached to the prototype; but when you replace the whole meta object with a new object, it overrides the property for that instance only.

Warning

Sharing state (nonmethod data) on a prototype property is commonly considered an anti-pattern in the JavaScript community, because accidental mutations of shared properties are a common source of bugs when you do it.

Prototype Cloning

Sometimes you don’t want to share data on a prototype property. Instead, you want each instance to have its own unique copy of the prototype’s properties. Popular JavaScript libraries have been shipping with a suitable method for cloning prototypes for several years. The cloning method is usually called .extend(). You pass in an object to extend, followed by any number of objects to extend from.

Unfortunately, extend() is not included in the JavaScript specification yet (Object.assign() works very similarly and is in JavaScript ES6). extend() is included in both jQuery and Underscore, and its implementation is simple. Here is the source from Underscore:

_.extend = function(obj) {
  each(slice.call(arguments, 1), function(source) {
    for (var prop in source) {
      obj[prop] = source[prop];
    }
  });
  return obj;
};

As you can see, it takes the first argument as a target (obj), iterates through remaining source arguments, and copies all of the public properties from each source to the target obj. The last object you pass in takes precedence if there are any property collisions.

Here’s how you use it to clone a prototype object:

var switchProto = {
      isOn: function isOn() {
        return this.state;
      },

      toggle: function toggle() {
        this.state = !this.state;
        return this;
      },

      meta: {
        name: 'Light switch'
      },

      state: false
    },

    switch1 = extend({}, switchProto),
    switch2 = extend({}, switchProto);

  test('Prototype clones.', function () {

    switch1.isOn.isShared = true;

    ok(!switch2.isShared, 
      'Methods are copied for each instance, not shared.'
    );

    ok(switch1.toggle().isOn(),
      '.toggle() works.'
    );

    ok(!switch2.isOn(),
      'instance safe.'
    );

    switch2.meta.name = 'Breaker switch';

    equal(switch1.meta.name, 'Breaker switch',
      'Object and array mutations are shared.'
    );

    switch2.meta = { name: 'Power switch' };

    equal(switch1.meta.name, 'Breaker switch',
      'Property replacement is instance-specific.'
    );
  });

In the extend() calls, you pass the new, empty object {} as the destination object, followed by the prototype switchProto as the source object.

The primary difference between cloning and delegation is that cloning will copy the value of each property for every object instance, whereas delegation is more memory efficient. It stores only one copy of each default property setting until you need to override properties at the instance level.

As it turns out, it’s often a good idea to employ a mix of both techniques—using the delegate prototype to share public methods between objects and cloning for data that can’t be safely shared between instances.

The Flyweight Pattern

The flyweight pattern conserves system resources by storing all reusable properties and methods on a delegate object, as opposed to storing copies of them on every instance. This can save a lot of memory and improve system performance dramatically if there are many objects of the same type.

In other languages, you have to jump through some hoops to set up a delegate object and defer all method calls and access to it. In JavaScript, the delegate prototype serves as a built-in flyweight delegate. You don’t need to worry about wiring it up yourself.

Imagine you’re programming a video game and there is a common enemy that has dozens or hundreds of copies in the game world. Each copy stores the enemy’s base stats, such as strength and speed, along with methods for all of its attacks and defenses. It also stores the enemy’s position in the game world and current health. You can optimize these objects in JavaScript by storing all of that data on the enemy prototype. When there is a change to the enemy’s health or position, those changes are made to the enemy instance, while all the other data and methods are delegated to the prototype:

var enemyPrototype = {
    name: 'Wolf',
    position: { // Override this with setPosition
      x: 0,
      y: 0
    },
    setPosition: function setPosition (x, y) {
      this.position = {
        x: x,
        y: y
      };
      return this;
    },
    health: 20, // Overrides automatically on change
    bite: function bite() {
    },
    evade: function evade() {
    }
  },

  spawnEnemy = function () {
    return Object.create(enemyPrototype);
  };

test('Flyweight pattern.', function () {
  var wolf1 = spawnEnemy(),
    wolf2 = spawnEnemy();

  wolf1.health = 5;
  ok(wolf2.health = 20,
    'Primitives override automatically.');

  ok(wolf1.setPosition(10, 10)
      .position.x === 10, 'Object override works.');
  equal(wolf2.position.x, 0,
      'The prototype should remain unchanged.');
});

Because moving data to the prototype delegate is so easy in JavaScript, it’s common to employ the flyweight pattern for nearly all object methods. That’s what’s going on when you see lines like this:

MyConstructor.prototype.myMethod = function () {
  // A method to be shared...
};

It’s less common to see the prototype employed for member data, but it’s a perfectly reasonable place to store default values that are commonly reused. Just be mindful that you’ll need to replace member objects and arrays rather than mutate them in place if you want your changes to be instance safe.

Object Creation

Objects in JavaScript are sometimes created with constructor functions. For example:

function Car(color, direction, mph) {
  this.color = color || 'pink';
  this.direction = direction || 0; // 0 = Straight ahead
  this.mph = mph || 0;

  this.gas = function gas(amount) {
    amount = amount || 10;
    this.mph += amount;
    return this;
  };

  this.brake = function brake(amount) {
    amount = amount || 10;
    this.mph = ((this.mph - amount) < 0)? 0
      : this.mph - amount;
    return this;
  };
}

var myCar = new Car();

test('Constructor', function () {
  ok(myCar.color, 'Has a color');

  equal(myCar.gas().mph, 10,
    '.accelerate() should add 10mph.'
  );

  equal(myCar.brake(5).mph, 5,
    '.brake(5) should subtract 5mph.'
  );      
});

You can get data encapsulation by using private variables:

function Car(color, direction, mph) {
  var isParkingBrakeOn = false;
  this.color = color || 'pink';
  this.direction = direction || 0; // 0 = Straight ahead
  this.mph = mph || 0;

  this.gas = function gas(amount) {
    amount = amount || 10;
    this.mph += amount;
    return this;
  };
  this.brake = function brake(amount) {
    amount = amount || 10;
    this.mph = ((this.mph - amount) < 0)? 0
      : this.mph - amount;
    return this;
  };
  this.toggleParkingBrake = function toggleParkingBrake() {
    isParkingBrakeOn = !isParkingBreakOn;
    return this;
  };
  this.isParked = function isParked() {
    return isParkingBrakeOn;
  }
}

var myCar = new Car();

test('Constructor with private property.', function () {
  ok(myCar.color, 'Has a color');
  equal(myCar.gas().mph, 10,
    '.accelerate() should add 10mph.'
  );
  equal(myCar.brake(5).mph, 5,
    '.brake(5) should subtract 5mph.'
  );
  ok(myCar.toggleParkingBrake().isParked(),
    '.toggleParkingBrake works.'
  );
});

You can shave a bit of syntax using the object-literal form:

var myCar = {
  color: 'pink',
  direction: 0,
  mph: 0,

  gas: function gas(amount) {
    amount = amount || 10;
    this.mph += amount;
    return this;
  },

  brake: function brake(amount) {
    amount = amount || 10;
    this.mph = ((this.mph - amount) < 0)? 0
      : this.mph - amount;
    return this;
  }
};

test('Object literal notation.', function () {
  ok(myCar.color, 'Has a color');

  equal(myCar.gas().mph, 10,
    '.accelerate() should add 10mph.'
  );

  equal(myCar.brake(5).mph, 5,
    '.brake(5) should subtract 5mph.'
  );
});

Notice that because the object-literal form doesn’t use a function, the encapsulation is gone.

Factories

Object literals have great advantages, but they offer no way to create data privacy. Encapsulation is useful because it hides implementation details from the client. Remember the first principle of OO design from the Gang of Four: “Program to an interface, not an implementation.” Encapsulation allows you to enforce that principle in your code, hiding implementation details from the user.

But you already know that constructor functions come with some drawbacks that are best avoided. A better solution is to use a factory method.

A factory is a method used to create other objects. Its purpose is to abstract the details of object creation from object use. In object-oriented design, factories are commonly used where a simple class is not enough.

Returning to the singleton example, sometimes it is useful to abstract the singleton reference behind a method call. You can make the singleton instance a private variable and return the reference from a closure:

function factory() {
  var highlander = {
      name: 'MacLeod'
    };
    
  return {
    get: function get() {
      return highlander;
    }
  };
}

test('Singleton', function () {
  var singleton = factory();
    hero = singleton.get(),
    hero2 = singleton.get();
  
  hero.sword = 'Katana';

  // Since hero2.sword exists, you know it's the same
  // object.
  ok(hero2.sword, 'There can be only one.');
});

You can use the same closure technique to add the parking break functionality to the car:

var car = function car(color, direction, mph) {
  var isParkingBrakeOn = false;

  return {
    color: color || 'pink',
    direction: direction || 0,
    mph: mph || 0,
    gas: function gas(amount) {
      amount = amount || 10;
      this.mph += amount;
      return this;
    },

    brake: function brake(amount) {
      amount = amount || 10;
      this.mph = ((this.mph - amount) < 0) ? 0
        : this.mph - amount;
      return this;
    },

    toggleParkingBrake: function toggleParkingBrake() {
      isParkingBrakeOn = !isParkingBrakeOn;
      return this;
    },

    isParked: function isParked() {
      return isParkingBrakeOn;
    }
  };
},
myCar = car('orange', 0, 5);

test('Factory with private variable.', function () {
  ok(myCar.color, 'Has a color');

  equal(myCar.gas().mph, 15,
    '.accelerate() should add 10mph.'
  );

  equal(myCar.brake(5).mph, 10,
    '.brake(5) should subtract 5mph.'
  );

  ok(myCar.toggleParkingBrake().isParked(),
    '.toggleParkingBrake() toggles on.');

  ok(!myCar.toggleParkingBrake().isParked(),
    '.toggleParkingBrake() toggles off.');
});

As with the constructor function, you get data privacy by encapsulating private data inside the closure, so the only way to manipulate the state of the parking brake is through the privileged method: .toggleParkingBrake().

Unlike the constructor function, you don’t have to invoke a factory with the new keyword (or worry about forgetting new, or guarding against clobbering the global object inside the function).

Of course, you can also take advantage of prototypes to make the whole thing more efficient:

var carPrototype = {
    gas: function gas(amount) {
      amount = amount || 10;
      this.mph += amount;
      return this;
    },
    brake: function brake(amount) {
      amount = amount || 10;
      this.mph = ((this.mph - amount) < 0)? 0
        : this.mph - amount;
      return this;
    },
    color: 'pink',
    direction: 0,
    mph: 0
  },

  car = function car(options) {
    return extend(Object.create(carPrototype), options);
  },

  myCar = car({
    color: 'red'
  });

test('Flyweight factory with cloning', function () {
  ok(Object.getPrototypeOf(myCar).gas,
    'Prototype methods are shared.'
  );
});

Notice that the factory method itself is now reduced to a one-liner. The arguments list is replaced with an options hash that allows you to specify exactly which values you want to override.

If you take advantage of the prototype feature, you can replace as much or as little of the prototype as you want at runtime. Using the same setup code as before:

test('Flyweight factory with cloning', function () {
  // Swap out some prototype defaults:
  extend(carPrototype, {
    name: 'Porsche',
    color: 'black',
    mph: 220
  });

  equal(myCar.name, 'Porsche',
    'Instance inherits the new name.'
  );

  equal(myCar.color, 'red',
    'No instance properties will be impacted.'
  );
});

Tip

You should avoid sharing objects and arrays on the prototype if they need to be instance safe. Instead, you can create new copies of the child object/array in the factory.

Prototypal Inheritance with Stamps

JavaScript’s object capabilities are really flexible, but Object.create() isn’t the easiest way to create a fully featured object. There are still quite a few hoops to jump through just to create a collection of flyweight objects that support data privacy. It gets even more complicated if you want to combine features from more than one source object.

Many libraries provide mechanisms to mimic classical inheritance, but there are few widespread libraries that simplify prototypal object creation, and certainly none that stand out as the gold standard. There is sugar for faking classes coming to JavaScript (I strongly discourage using it). What would it look like if we created sugar for prototypal OO that supported all of the best features JavaScript has to offer?

When thinking about object creation in JavaScript, it helps to ask, what are the important features of objects in JavaScript?

  • Delegate prototype

  • Instance state

  • Encapsulation

A stamp is a factory function that has public properties that specify a delegate prototype, default instance state, and a function that sets up encapsulation for object instances. Stamps utilize three different types of inheritance to create the new object:

  • Delegate prototype: delegation/differential inheritance

  • Instance state: cloning/concatenative inheritance/mixins

  • Encapsulation: functional inheritance

Stampit is a library written for this book to demonstrate how we might use sugar to simplify prototypal OO. It exports a single function. Here’s the signature:

stampit(methods, state, enclose);

Here’s a more detailed look at how you’d use it to create an object from scratch:

var testObj = stampit(
// methods
{
  delegateMethod: function delegateMethod() {
    return 'shared property';
  }
},

// state
{
  instanceProp: 'instance property'
},

// enclose
function () {
  var privateProp = 'private property';

  this.getPrivate = function getPrivate() {
    return privateProp;
  }
}).create();

test('Stampit with params', function () {
  equal(testObj.delegateMethod(), 'shared property',
    'delegate methods should be reachable');

  ok(Object.getPrototypeOf(testObj).delegateMethod,
    'delegate methods should be stored on the ' +
    'delegate prototype');

  equal(testObj.instanceProp, 'instance property',
    'state should be reachable.');

  ok(testObj.hasOwnProperty('instanceProp'),
    'state should be instance safe.');

  equal(testObj.hasOwnProperty('privateProp'), false,
    'should hide private properties');

  equal(testObj.getPrivate(), 'private property',
    'should support privileged methods');
});

Notice that the .create() method was called on the returned stamp in order to return the testObj instance. The .create() method simply returns a new object instance from the stamp. As you can see from the tests, all of the great features that make JavaScript’s object system special are available without jumping through all the hoops of setting up your own factory function, figuring out where to store prototypes, and so on.

The stamps returned by stampit() also contain methods that can be chained to further define the stamp. This is equivalent to the preceding stamp:

var testObj = stampit().methods({
    delegateMethod: function delegateMethod() {
      return 'shared property';
    }
  })
  .state({
    instanceProp: 'instance property'
  })
  .enclose(function () {
    var privateProp = 'private property';

    this.getPrivate = function getPrivate() {
      return privateProp;
    }
  })
  .create();

The new object gets created with Object.create() using methods as the delegate prototype. Delegate methods are shared among all object instances, which conserve memory resources. If you change a prototype property at runtime, the value change is reflected on every instance of the object. To demonstrate:

var stamp = stampit().methods({
    delegateMethod: function delegateMethod() {
      return 'shared property';
    }
  }),
  obj1 = stamp(),
  obj2 = stamp();

Object.getPrototypeOf(obj1).delegateMethod = 
  function () {
    return 'altered';
  };

test('Prototype mutation', function () {
  equal(obj2.delegateMethod(), 'altered',
    'Instances share the delegate prototype.');
});

The .state() method uses concatenative inheritance, which creates a copy of each property from the state prototypes to the new object, allowing you to safely store instance state. All stamps take an options hash that will be mixed into the instance properties, so it’s trivial to initialize a new object:

var person = stampit().state({name: ''}),
  jimi = person({name: 'Jimi Hendrix'});


test('Initialization', function () {

  equal(jimi.name, 'Jimi Hendrix',
    'Object should be initialized.');

});

The .enclose() method uses functional inheritance, which invokes the functions you pass in against the newly created object. You can pass in any number of .enclose() functions. Private data will not collide, because a unique closure will be created for each function. Privileged methods will override methods of the same name. Last in wins.

Sometimes it’s useful to initialize an object with parameters that don’t correspond 1:1 with object properties. The way I prefer to do that is to decouple object instantiation and object initialization. You can do that by creating setters on the object:

var person = stampit().enclose(function () {
  var firstName = '',
    lastName = '';

  this.getName = function getName() {
    return firstName + ' ' + lastName;
  };

  this.setName = function setName(options) {
    firstName = options.firstName || '';
    lastName = options.lastName || '';
    return this;
  };
}),

jimi = person().setName({
  firstName: 'Jimi',
  lastName: 'Hendrix'
});

test('Init method', function () {

equal(jimi.getName(), 'Jimi Hendrix',
  'Object should be initialized.');

});

Of course, creating new objects is just scratching the surface of JavaScript’s OO capabilities. What you’re about to see is not possible with any currently existing popular JavaScript class library. It’s not possible with the ES6 class keyword, either.

First, you’ll use a closure to create data privacy:

var a = stampit().enclose(function () {
  var a = 'a';

  this.getA = function () {
    return a;
  };
});

a().getA(); // 'a'

It uses function scope to encapsulate private data. Note that the getter must be defined inside the function in order to access the closure variables. All privileged functions in JavaScript must be defined within the same scope as the private variables they need access to.

And another:

var b = stampit().enclose(function () {
  var a = 'b';

  this.getB = function () {
    return a;
  };
});

b().getB(); // 'b'

Those a’s are not a typo. The point is to demonstrate that a and b’s private variables won’t clash. Here’s where it gets interesting:

var c = stampit.compose(a, b),
  foo = c();

foo.getA(); // 'a'
foo.getB(); // 'b'

Stampit’s .compose() method allows you to inherit all three types of prototypes from any number of stamps. The preceding example demonstrates inheritance from multiple ancestors, including private data. Classical OO as we know it today has got nothing on this.

Each stamp has a special property called fixed, which stores methods, state, and enclose prototypes. When the stamp is invoked, the state prototype is copied so that it is instance safe, the methods property is used as the delegate prototype, and each enclose function is called in the order in which it was created to set up data privacy (last in wins in the case of name collisions).

The .compose() method works a bit like $.extend(), but instead of extending objects with the properties of other objects, it extends new objects with the fixed prototypes from the factories you pass in, and then calls Stampit and passes them into a new stamp. Like $.extend(), _.extend(), and so on, last in wins when names collide, which makes it trivial to override stamp features.

Conclusion

Stampit is in production use in web applications with tens of millions of users, so the full source contains several shims for older browsers that enable JavaScript ES5 features. Despite that, it weighs in at about 4 k minified and gzipped. The meat of it is about 90 lines of code (without the shims and comments).

As you can see, JavaScript’s object system is flexible and powerful enough to do some really amazing things with very little effort. Imagine how much more fun it could be with a little more built-in language sugar for working with prototypes. Object. create() is a good start, but we could do a lot more. By now you should have a whole new respect for prototypes and JavaScript’s object system.

Interest in inheritance seems to be waning as Node.js gains popularity. Part of the reason for that is modules. Modules compete with inheritance indirectly but do supply an alternative to inheritance as a code reuse mechanism. Stampit uses Node-style modules to reuse features from a modular utility library. The fact that the library is modular means that Stampit only gets the functionality it needs, and no more. Unlike classical inheritance, modules allow you to pick and choose which features you require.

Get Programming JavaScript Applications 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.