Friday, January 29, 2016

Object Creation in JavaScript and the "class" keyword

The most requested and contentious addition in ES6 is the class keyword. The class keyword is special syntax that allows you to build a function that creates objects. The reason people want this is because the basic object construction in JavaScript is awful and weird. Here is a quick sample:

function MyObject(param 1, param2) {
    this.param1 = param1;
    this.param2 = param2;


MyObject.prototype.method1 = function() { ... };
MyObject.prototype.method2 = function() { ... };

This looks really odd. Why is the word prototype there? What is 'this' in the MyObject function? Why does MyObject look like a normal function but have to be called with new? Can you call it without new? Where is the return statement?

Coming to this pattern for the first time is horribly confusing. To understand how basic object creation works you need to understand the language at a deeper level than most people do when they first approach it. Crockford says that the problem is that people programming JavaScript don't want to take the time to learn JavaScript. I personally think this is a horrible way to generate a constructor function and that the pattern is confusing, but I agree with Crockford in that the "class" keyword is not the answer. Crockford presents a pattern for object creation like so:

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

}

He focusses on security and abandons prototypes. His argument about prototypes is basically one of premature optimization. Using prototypes instead of placing functions directly on objects is premature optimization because you don't know if you actually have a problem and he contends that you probably won't have a problem.

I work with TypeScript and I continually feel constrained by it. I can not touch the prototype (which according to Crockford, may not be a bad thing) easily. Mixins are painful to do. I dislike the class keyword, but the confusing, and worse, unencapsulated basic pattern for objects is very ugly. Here is a pattern that I have been toying with to be more powerful than "class", use prototypes unlike Crockford, and look a little nicer.

var ObjectMaker = (() => {
    /* private class functions */
    var private1 = () => { ... }
    var private2 = () => { ... }

    /* private class functions */
    var publicClassFunctions = {
        public1: () => { ... },
        public2: () => { ... }
    }

/* function that constructs object */
  return (constructionParams) => {
var baseObject = Object.create(publicClassFunctions); 
... other stuff in object creation ...
return baseObject;
    }

})()

This has a clear section for private functions that can be access by public class functions and anything inside the constructor because of the closure created by the IIFE. This construct does kind of ask you to understand the notion of closure, but I would say that you need to understand this concept if you are going to write JavaScript that has constructors. You can certainly write simple JavaScript and not use constructors. 

The thing about JavaScript is that it gives you flexibility because of things like: object literals, closures, and first class functions. With a little knowledge of the language you can choose a pattern to use to create constructors. You may even find that the method you use to create the object depends a lot on how the object is to be used. For example you may have an object you just want one of, aka a singleton. Why write a constructor at all? Just build it with an object literal. Have an object that you only expect to have under 10 of? Why bother using prototypes. Maybe you have 100,000 objects that share a large set of complex functions. Well, prototypes are probably the way to go.

In closing, the class keyword is not needed if you have engineers simply take the time to learn the basics of the language instead of assuming JavaScript and Java should be the same.

No comments:

Post a Comment