JavaScript

Classical Inheritance is Obsolete – How to Think in Prototypal OO

That’s right. I said it. To a packed room at the O’Reilly Fluent Conference: JavaScript and Beyond, 2013. And I’ll say it again: Classical inheritance is obsolete. Classes are dead. They just don’t know it, yet. 😉

Check out the corresponding blog post, “Fluent JavaScript – Three Different Kinds Of Prototypal OO”.

See also:

Standard
JavaScript, Node

Stampit 0.3 Released

Right on the heels of Stampit 0.2, there’s a new release. Stampit 0.3 works with Node, Browserify, AMD, Bower, and a plain old browser global if you’re still using those. Tested with IE8+, Chrome, Firefox, Safari, and Android.

Another convenient addition has landed, as well. Now you can do _.extend() style mixins just by passing multiple objects into .methods() or .state().

Stampit lets you create objects from reusable, composable behaviors. If you’re new to stampit, check out “Three Different Kinds of Prototypal OO”.

Enjoy!

Standard
JavaScript

Fluent JavaScript – Three Different Kinds of Prototypal OO

Note: I’ve presented this as a talk a couple of times. You can see the latest version from O’Reilly’s Fluent Conference: JavaScript and Beyond, 2013. The talk is called “Classical Inheritance is Obsolete: How to Think in Prototypal OO”.

In order to claim fluency in JavaScript, it’s important to understand how JavaScript’s native inheritance capabilities work. This is an often neglected area of JavaScript writing and learning, but understanding it can be dramatically empowering.

JavaScript is one of the most expressive programming languages ever created. In particular, its combination of delegate prototypes, runtime object extension, and closures allow you to express three distinct types of prototypes in JavaScript. Let’s take a closer look at each of these.

Delegation / Differential Inheritance

A delegate prototype is an object that serves as a base for another object. When you inherit from a delegate prototype, the new object gets a reference to the prototype. When you try to access a property on the new object, it checks the object’s own properties first. If it doesn’t find it there, it checks the prototype, and so on up the chain until it gets back to Object.prototype.

Method delegation is a fantastic way to preserve memory resources, because you only need one copy of each method to be shared by all instances. It’s also a great way to add capabilities at runtime to all objects which share a particular prototype.

There are a couple of ways to set up that relationship in JavaScript. The one you’re likely to see in a lot of books goes something like this:

function Greeter(name) {
  this.name = name || 'John Doe';
}

Greeter.prototype.hello = function hello() {
  return 'Hello, my name is ' + this.name;
}

var george = new Greeter('George');

See JavaScript Constructor Functions vs Factory Functions and Stop Using Constructor Functions in JavaScript for my thoughts on why you should ignore this technique. I present it here only because it’s likely to be a familiar point of reference.

I prefer this:

var proto = {
  hello: function hello() {
    return 'Hello, my name is ' + this.name;
  }
};

var george = Object.create(proto);
george.name = 'George';

The one major drawback to delegation is that it’s not very good at storing state. In particular, if you try to store state as objects or arrays, mutating any member of the object or array will mutate the member for every instance that shares the prototype. In order to preserve instance safety, you need to make a copy of the state for each object.

Cloning / Concatenative Inheritance / Mixins

Prototype cloning is the process of copying the properties from one object to another, without retaining a reference between the two objects. Cloning a great way to store default state for objects. This process is commonly achieved by methods like Underscore’s .extend(), or jQuery’s .extend():

var proto = {
  hello: function hello() {
    return 'Hello, my name is ' + this.name;
  }
};

var george = _.extend({}, proto, {name: 'George'});

It’s common to see this style used for mixins. For example, Backbone users can make any object an event emitter by extending from Backbone.Events:

var foo = _.extend({
  attrs: {},
  set: function (name, value) {
    this.attrs[name] = value;
    this.trigger('change', {
      name: name,
      value: value
    });
  },
  get: function (name, value) {
    return this.attrs[name];
  } 
}, Backbone.Events);

Closure Prototypes / Functional Inheritance

I’m cheating on the name for this one. It’s not really functional, and it’s not an object prototype. It’s a function prototype. Think of it as an alternative to a constructor / init function. It can be copied (inherited) from one factory to another, and combined with other functions like it to completely replace the need for super() (which is a code smell, and should be avoided).

Closure prototypes are functions that can be run against a target object in order to extend it. The primary advantage of this style is that it allows for encapsulation. In other words, you can enforce private state. Douglas Crockford called this style “functional inheritance” in his book, “JavaScript: The Good Parts”. It looks something like this (Foo, like above, with private attributes):

var model = function () {
  var attrs = {};

  this.set = function (name, value) {
    attrs[name] = value;
    this.trigger('change', {
      name: name,
      value: value
    });
  };

  this.get = function (name, value) {
    return attrs[name];
  };

  _.extend(this, Backbone.Events);
};

model.call(george, 'Top secret');

george.on('change', function (e) { console.log(e); });

george.set('name', 'Sam'); // Object {name: "name", value: "Sam"}

This is all well and good, but there’s an awful lot of jumping through hoops if you want to combine the techniques — so I wrote a little library to jump through the hoops for you. It’s called Stampit.

Stampit

Create objects from reusable, composable behaviors.

Features

  • Create functions (called factories) which stamp out new objects. All of the new objects inherit all of the prescribed behavior.
  • Compose factories together to create new factories.
  • Inherit methods and default state.
  • Supports composable private state and privileged methods.
  • State is cloned for each instance, so it won’t be accidentally shared.
  • For the curious – it’s great for learning about prototypal OO. It mixes three major types of prototypes:
    1. differential inheritance, aka delegation (for methods),
    2. cloning, aka concatenation/exemplar prototypes (for state),
    3. functional / closure prototypes (for privacy / encapsulation)
  • What’s the Point?

    Prototypal OO is great, and JavaScript’s capabilities give us some really powerful tools to explore it, but it could be easier to use.

    Basic questions like “how do I inherit privileged methods and private data?” and “what are some good alternatives to inheritance hierarchies?” are stumpers for many JavaScript users.

    Let’s answer both of these questions at the same time. First, we’ll use a closure to create data privacy:

    var a = stampit().enclose(function () {
      var a = 'a';
      this.getA = function () {
        return 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.

    Let’s see if that worked:

    a(); // Object -- so far so good.
    a().getA(); // "a"
    

    Yes. Got it. In both of these instances, we actually created a brand new object, and then immediately threw it away, because we didn’t assign it to anything. Don’t worry about that.

    Here’s another:

    var b = stampit().enclose(function () {
      var a = 'b';
      this.getB = function () {
        return a;
      };
    });
    

    Those `a`’s are not a typo. The point is to demonstrate that `a` and `b`’s private variables won’t clash.

    But here’s the real treat:

    var c = stampit.compose(a, b);
    
    var foo = c(); // we won't throw this one away...
    
    foo.getA(); // "a"
    foo.getB(); // "b"
    

    WAT? Yeah. You just inherited privileged methods and private data from two sources at the same time.

    But that’s boring. Let’s see what else is on tap:

    // Some more privileged methods, with some private data.
    // Use stampit.extend() to make this feel declarative:
    var availability = stampit().enclose(function () {
      var isOpen = false; // private
    
      return stampit.extend(this, {
        open: function open() {
          isOpen = true;
          return this;
        },
        close: function close() {
          isOpen = false;
          return this;
        },
        isOpen: function isOpenMethod() {
          return isOpen;
        }
      });
    });
    
    // Here's a mixin with public methods, and some state:
    var membership = stampit({
        add: function (member) {
          this.members[member.name] = member;
          return this;
        },
        getMember: function (name) {
          return this.members[name];
        }
      },
      {
        members: {}
      });
    
    // Let's set some defaults: 
    var defaults = stampit().state({
            name: 'The Saloon',
            specials: 'Whisky, Gin, Tequila'
          });
    
    // Classical inheritance has nothing on this. No parent/child coupling. No deep inheritance hierarchies.
    // Just good, clean code reusability.
    var bar = stampit.compose(defaults, availability, membership);
    
    // Note that you can override state on instantiation:
    var myBar = bar({name: 'Moe's'});
    
    // Silly, but proves that everything is as it should be.
    myBar.add({name: 'Homer' }).open().getMember('Homer'); 
    
    Standard