Why I prefer using new/prototype/this to ‘createClass’?

Here is my thoughts on “factory” vs. “new/class”. First I agree that class is not necessary when we use prototype system in javascript. And prototype is superior than class, that’s why we love javascript.

But when we design a system, we need some tool to help use minify the side effects between your internal API calls. Making zero side effects system is possible, but that doesn’t make too much sense. Closure is a important feature in javascript, the closure is mutable, we use that commonly to reserve state in function. This is not pure functions anymore, but that’s an sweet spot in the middle of the spectrum from pure functional programming to none-pure functional programming. So the rules of thumb here is localize the side effects, and make the side effects physically close to functions. That’s one style we use to describe how Object Oriented Design marry with functional programming happily.

The previous chapter help us explain why the prototype is good. We can use the object to localize their local states (side effects), and the prototype is the functions which apply side effects on them. This style help us get rid of the dirts from classical OO’s class system. So here is a new question, do you think the class and new harmful in javascript? My answer is NO.

So the intention of the functional and localized side effects is a goodwill, and we should think about what’s the right tool/pattern for us to achieve that? And there’re 2 common patterns in javascript to achieve that.

  1. Factory:
var User = function() {
    var privateState = {}

    var setPrivateState = function(value1) {
        privateState.state1 = value1;
    }

    return {
        publicMethod: function(value1) {
            setPrivateState(value1);
            this.otherPublicMethod();
        },
        otherPublicMethod: function() {}
    }
}
var user = User();
  1. Use function, prototype and new:
var User = function constructor() {
    this.privateState = {}
}

User.prototype = Object.create({
    _setPrivateState: function(value1) {
        this.privateState.state1 = value1;
    },
    otherPublicMethod: function() {}
});

User.prototype.publicMethod = function(value1) {
    this._setPrivateState(value1);
    this.otherPublicMethod();
}

var user = new User();

The Factory use closure simulate private methods and variable, the reference of this is inexplicit reference the returned object literal itself. The magical stuff is that the Factory way don’t need the new keyword, which is the reason why someone love it.

The prototype way lost the private method/variable (you can do that by define some private method inside the constructor, but let’s put that aside). But the benefit is explicit this binding in new, and having a prototype chain in new (that’s how the prototype chain works). Although prototype chain is commonly used for simulating inherit (which is bad), but we can also doing mixin by prototype (which shares all methods on prototype; in comparison, mixing is normally done as method copy between objects in Factory way).

Because the prototype is a killer feature IMHO, so I lean towards using the new/prototype/class pattern. I don’t have strong opinion on the keyword new (because I have some friends don’t like it), but let’s review what’s new is doing?

  1. A new object is created, inheriting from foo.prototype.
  2. The constructor function foo is called with the specified arguments and this bound to the newly created object. new foo is equivalent to new foo(), i.e. if no argument list is specified, foo is called without arguments.
  3. The object returned by the constructor function becomes the result of the whole new expression. If the constructor function doesn’t explicitly return an object, the object created in step 1 is used instead. (Normally constructors don’t return a value, but they can choose to do so if they want to override the normal object creation process.)

So I think new is still quite useful 🙂

Going back to the implementation side. Using the new/prototype/class is my choice, but there’s some drawback. The prototype is very flexible, and we may misuse it. I’m especially against using that for inheritance reuse. Because most people believe composition over inheritance (for reuse).

So what I need?

  • Make clear that we need a constructor for a object factory (I don’t call it class)
  • We define a set of own methods for that object, and they should be assign into constructor’s prototype
  • We’d like to use mixin (on prototype) to reuse

And probably you know that React is hot in our community. And react have a method React.createClass, which is doing exactly that 3 thing I describe above. It’s like a factory of object factory, put some restriction to you, but showing you a schema of a object factory. I like it. But you don’t need React to use createClass, you can do it with couple of lines of code.

var _ = require(‘underscore’);

var createClass = function(options) {
    options = options || {};

    var constructor = options.hasOwnProperty(‘constructor’) ? options.constructor : (function() {});
    delete options.constructor;
    var mixins = options.mixins;
    delete options.mixins;

    options.mixin = _.mixin;
    constructor.prototype = options;

    if (mixins) {
        mixins.forEach(function(mixin) {
            _.extend(constructor.prototype, mixin);
        });
    }

    return constructor;
}

I used methods in underscore, you can copy them out and have a standalone createClass.

How about class support in coffeescript and ES6? I’m a believer of both. I use coffeescript for years, and I love it’s class implementation. The class support doesn’t give you mixin out of box, because mixin is a personal choice. So the class is just a factory of object factory, which is same as what we introduce above.

The how is not very important in this post, because you can write your own (better) implementation easily. The more important is why we doing this, the core is adopt functional and localized side effects design style.

One thought on “Why I prefer using new/prototype/this to ‘createClass’?”

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.