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.
- 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();
- 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?
- A new object is created, inheriting from foo.prototype.
- 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.
- 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.