Web developmentWritten on

JavaScript classes the old way

The number one blog post on the old iteration of this site was about writing modular JavaScript using jQuery. Today we use the class declaration a lot to create objects because we can and because it's convenient.

But JavaScript is a prototypical language and it might be nice to look a bit under the hood to use interesting features from that type of programming. So let's say we have a little sample class:

const DEFAULTS = {
  debug: false
};

class App {
  // constructor
  constructor(settings) {
    this.config = Object.assign({}, DEFAULTS, settings);
  }

  // Adding a instance method
  run() {
    console.log(`Running... debug: ${this.config.debug}`);
  }
}

// Creating a new instance
const app = new App({debug: true});
app.run();

Ok, thats simple and easy. Now let's see what this does look like without using the ES6 features:

var DEFAULTS = {
  debug: false
};

// constructor
function App(settings) {
    this.config = Object.assign({}, DEFAULTS, settings);
}

// Adding the instance method
App.prototype.run = function () {
    console.log("Running... debug: " + this.config.debug);
};

// Creating a new instance
const app = new App({debug: true});
app.run();

The instantiation is actually the same. The difference is, that there is this weird looking App function which is the actual class and the constructor. The methods for the instantiated objects are added to App.prototype and will be magically there in the instance. The funn thing is that we can extend this prototype later even for all instances -- eerrr, what?

Ok, let's say we did already run that code and now in the browser or somewhere we want to extend the App to have some testing (or something) just for the moment:


// Let's instantiate some apps
var app01 = new App({name: "app01"});
var app02 = new App({name: "app02"});

// Oh, let's test...
App.prototype.test = function () {
  console.log("name:", this.config.name);
};

// Run it...
app01.test();
app02.test();

We did change the prototype and added the feature to all already instantiated objects of App. And the whole thing actually works for the ES6 classes, too. As said the class declaration is just syntactic sugar for the prototype notation.

That's really nice to know and can be really neat sometimes. Of course developers coming from Java will say that it's really dangerous and unsafe and whatever. Just let them use their class declaration and let them be happy. For all others: This can be a really cool feature to write extensions for your app.

In case you need to support legacy browsers: You don't need to write App.prototype. all the time. I usually do this:

var DEFAULTS = {
  debug: false
};

// constructor
function App(settings) {
    this.config = Object.assign({}, DEFAULTS, settings);
}

// Passing the prototype by reference to `proto`
var proto = App.prototype;

// Adding the instance method
proto.run = function () {
    console.log("Running... debug: " + this.config.debug);
};

// Creating a new instance
const app = new App({debug: true});
app.run();

That way I do not need to write that long string all the time and it's easier to rename the whole object without needing to rename all the assignments.

Ok, that's all what was (essentially) covered in the old blog post. Hope this helps and thanks for programming with me today.