Crockford’s 2014 object creation pattern

Douglas Crockford has long advocated for relatively unusual object creation patterns that do away with the “new”, and now the “this” keywords altogether. While watching a recent talk that he gave about the better parts of EcmaScript 6, I spotted the evolution of his pattern for the new version of the language. I haven’t found it explained anywhere else so far, so I thought I’d try to deconstruct it in a post…

Here’s the new pattern as it appears in the slides:

function constructor(spec) {
let {member} = spec,
{other} = other_constructor(spec),
method = function () {
// member, other, method, spec
};
return Object.freeze({
method,
other
});
}

It’s important to note that this makes heavy use of EcmaScript 6 constructs, and thus is not applicable just yet in current execution environments, whether that’s the browser or Node. The pattern can be easily adapted for earlier versions of EcmaScript, although it would lose some of its properties, and be less concise. Before we do, let’s look at the code and deconstruct it.

The “let” keyword is the new “var”. It has better scoping rules, and enables some interesting assignment constructs, such as the one you see here. “let {member} = spec” is equivalent to “let member = spec.member”. Personally, I don’t find that very expressive or readable, but that’s what it is, and as we’ll see, it does make code a lot more DRY. It’s called destructuring, and it has some really nice applications, but this one is one of the more obscure usages. In an actual example (see below), you’d have more assignments than that, which makes it a little clearer:

{memberA, memberB, memberC} = spec

This effectively creates private fields from constructor parameters, that methods can use.

The next line calls another constructor function, using destructuring again. The other constructor is called with the same spec parameters, and its return values are destructured across one or several other private fields. Again, there is no reason to limit this to just one variable, and you could have instead:

{otherMemberA, otherMemberB} = other_constructor(spec)

This effectively “inherits”, or rather composes the behavior of another object into the current object. Note that multiple constructors can be called in the same way. This is composition rather than multiple inheritance, which is very nice.

Next, we have one or several method declarations. Those methods, of course, close over all the previous declarations, as well as the spec object, and can make use of them freely.

Finally, a frozen public API is returned from the constructor. Notice how the returned object uses the new EcmaScript 6 value shorthand, which removes unnecessary and noisy labels. The object there is equivalent to this:

{method: method, other: other}

I’m not sure I like the freezing here. If the application requires that sort of immutability, it seems fine, but it looks a little overkill to me otherwise. You could just as well return the same object without freezing it, it seems, without too many bad consequences.

Let’s see how this would look in a less abstract example:

function blogPost(spec) {
let {url, title, body, tags} = spec,
{buildSlug} = routable(spec),
{addTag, removeTag} = taggable(spec),
extractSummary = function () {
// TODO: be more subtle
return body.substring(0, 200);
};
return Object.freeze({
extractSummary,
buildSlug,
addTag, removeTag
url, title, body, tags
});
}

This would look like this in current JavaScript:

function blogPost(spec) {
var url = spec.url;
var title = spec.title;
var body = spec.body;
var tags = spec.tags;

var buildSlug = routable(spec).buildSlug;

var taggable = taggable(spec);
var addTag = taggable.addTag;
var removeTag = taggable.removeTag;

var extractSummary = function () {
// TODO: be more subtle
return body.substring(0, 200);
};

return {
extractSummary: extractSummary,
buildSlug: buildSlug,
addTag: addTag,
removeTag: removeTag,
url: url,
title: title,
body: body,
tags: tags
};
}

Much more verbose, even if I could have removed all “var” but one (which I don’t like to do if you must know). Are you starting to like the new EcmaScript 6 features yet?

The pattern creates copies of methods on each instance of the object, which is something that some people resent, as it trades memory pressure for some perf benefits (lookups for methods don’t have to go very deep in the prototype chain). Crockford’s argument is basically that memory is no longer an issue, unless you’re going to create hundreds of thousands of such objects. Premature optimization and such. I’d agree with him in most situations.

Avoiding “new” and “this” is also a debatable practice. I was never too bothered by them. I never forgot a “new”, and thinking about what “this” means in a specific context doesn’t bother me too much. Actually, I think creating an object from a regular function call always looks a little weird to me, but I suppose that’s the C# background speaking. I could frankly go either way on this one.

Another downside is that this pattern doesn’t care at all about the prototype chain, and breaks operators such as instanceof. Not something I particularly care about, but definitely something to have in mind when deciding whether to use this.

One thing that I do like without reservation about the pattern however, is how it emphasizes composition over classical multiple inheritance patterns. Having avoided even single inheritance as much as possible in JavaScript and in other languages, I find this appealing.

A final remark could be that there are many facets to this 2014 version of Crockford object instantiation, which seemingly represent the current state of his thinking on the subject. You don’t have to adopt all of those facets as a whole. Instead, one can very well pick and choose the parts he likes, and adapt it to taste and requirements.

1 Comment

  • Crockford covers this in some detail in JavaScript: The Good Parts. There, one version allows passing in a second parameter to serve as data *within the hierarchy*, and leads to interesting object graphs.

Comments have been disabled for this content.