Home Blog CV Projects Patterns Notes Book Colophon Search

Crockford's Latest Constructor Pattern

In 2014 Douglas Crockford updated his advice not to use Object.create() and instead to do this with ES6:

https://youtu.be/PSGEjv3Tqo0?t=1506

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

Here member is one thing extracted from spec, (you could extract more things too), other is something extracted from another constructor, method is something we've created ourselves, and Object.freeze() returns a new object made up of all these parts, but one that can't be modified.

Example:

function thing(spec) {
  let {name} = spec,
      printName = function() {
        console.log(`${name}\n`);
      }
  return Object.freeze({
    name,
    printName
  });
}

function person(spec) {
  let {name, printName} = thing(spec);
  return Object.freeze({
    name,
    printName
  });
}

const alice = person({name: 'Alice'});
const bob = person({name: 'Bob'});

alice.printName();
bob.printName();

Gives:

Alice
Bob

(You can try it in your browser console too if you like, refresh the page if you want to run the code a second time).

To deal with properties that you want to be able to change when you want other things fixed you can use getters and setters. Here's an example:

function point(spec) {
  let {latitude, longitude} = spec;
  return Object.freeze({
    constant: "constant",
    get latitude() { return latitude },
    set latitude(value) { latitude = value },
    get longitude() { return longitude },
    set longitude(value) { longitude = value },
  });
}

Here's how to use it:

const data = {latitude: 1, longitude: 2}
const p = point(data);
console.log(p.latitude);
p.latitude = -0.109
console.log(p.latitude);
console.log(JSON.stringify(p, null, 4));
console.log(data);

This all works as you'd expect, without the original data object being changed:

1
-0.109
{
    "constant": "constant",
    "latitude": -0.109,
    "longitude": 2
}
{ latitude: 1, longitude: 2 }

Because we used Object.freeze() that the constant key cannot be changed or deleted and new keys cannot be added. Any attempts are silently ignored.

This code:

p.constant = "changed";
delete p["constant"];
p["newkey"] = "value";
console.log(p);
console.log(JSON.stringify(p, null, 4));

Gives the same data as before:

{ constant: 'constant',
  latitude: [Getter/Setter],
  longitude: [Getter/Setter] }
{
    "constant": "constant",
    "latitude": -0.109,
    "longitude": 2
}

Tip: If you don't want the errors silently ignored you can run the code in strict mode. For Node that means adding "use strict"; to the top of the file or running with node --use_strict.

Copyright James Gardner 1996-2020 All Rights Reserved. Admin.