Pallet Town: Giving Into Javascript Classes

Jul 27, 2017 | JavaScript, Programming

Coder Radio listeners will know that I have some strong feelings on classes in Javascript and most of them are pretty negative. After some extensive time (measured in years) of exploring alternatives to pure Javascript such as CoffeeScript and Typescript, I ended up going back to pure Javascript but remained Typescript curious. That takes us to the present day. I find myself working on a very large, feature rich, and complex Javascript codebase that other people will eventually be working on with me. I’ve long railed that classical inheritance has no place in Javascript, but the reality of the situation is that it makes sense for some use cases and (a much more severe issue) most developers you’d hire out of school and sadly many more experience ones have no frame of reference outside of the classical OO as seen in languages like Java and C#.

Presented with this combination of issues, I naturally looked to include some Typescript classes in my code for some underlying data structures that the software is going to rely on. Unfortunately, I hit a pretty fast issue — require statements. My code base is based on Node.js and uses require heavily. In simple cases, that’s no problem in simple cases:

var Pokemon = require('pokemon') // Javascript

import Pokemon from 'pokemon' // Typescript

That’s not so bad, but things can get a little less elegant very fast. For instance, let’s say you’re using MongoDB and importing it via require:

var MongoClient = require('mongodb').MongoClient

There are of course ways to do this but none of them were elegant and simple enough for my tastes. As an aside, if your application uses MongoDB via the Mongoose driver, then you’re good to go with this Typescript statement:

import * as mongoose from 'mongoose'

My application, however, is using the Mongo driver directly and for some business specific reasons this was not an option, so I said ’so long to Typescript’ for this project and looked for another solution to my classical OO problem.

The solution I landed on was using the class functionality introduced in Javascript in ES6. Let’s take a look at a sample of what this might look like assuming that were are working on a Node.js based application that needs to pull in Mongo in the same way that my real world one does:


// importing Mongo

var MongoClient = require('mongodb').MongoClient;
var mongo_url = 'some_url_for_database_access';
// class declaration
class Pokemon {
    constructor(name, type, level) {
        this.name = name;
        this.type = type;
        this.level = level;
    }
    
    save(callback) {
        let pokemon = this;
        MongoClient.connect(mongo_url, function (err, db) {
            if (err) throw err;
            db.collection('pokemon').insertOne(JSON.stringify(pokemon), function (err, result) {
                if (err == null) callback();
            }); 
        }
    }
}
module.exports = Pokemon; // exporting for use elsewhere

That’s a pretty simple implementation but is enough to get a good idea of the basic structure of Javascript classes. One aspect that I am finding interesting about working with them is that it’s possible (and as far as I can see a good practice) to use them as sparingly as possible, hopefully avoiding the deep coupling between classes that tends to occur in large scale applications written in a classical OO style. So far, my thinking is that these types of classes are appropriate for base data structures that your application relies on, but the majority of your code should be written in a more functional style.

I hope this helps and if you want to reach out please find me on Twitter and if you’re interested in seeing something cool pretty soon check out The Mad Botter.

More from Mike:

About Me

Hi! I’m Mike! I’m a software engineer who codes at The Mad Botter INC. You might know me from Coder Radio or The Mike Dominick Show.  Drop me a line if you’re interested in having some custom mobile or web development done.

Follow Me

© 2024 Copyright Michael Dominick | All rights reserved