[Coding] JavaScript Patterns (Ch. 3)

Posted by Khatharsis on June 14, 2013

This chapter focused on objects, arrays, primitive types (number, string, boolean), and errors. It’s a fairly high overview of the topics, but there were some gems I wasn’t aware of.

Objects can be thought of as key-value pairs, like hash tables. The keys can point to primitives or objects, in which case the values are properties. Keys can also point to functions, in which case the values are methods. Objects created in JavaScript can be changed (functionality added to or removed from) at any time. There is no such thing as an empty object because an object inherits properties and methods from Object.prototype. An empty object often refers to an object that has no properties and methods of its own, other than those it has inherited.

Objects can be initialized two ways:
-Literal: var obj = {}
-Constructor: var obj = new Object()

It is preferable to use the literal because it’s shorter and emphasizes the class-less structure of JavaScript. When using the constructor, a parameter may be passed, such as a primitive type, and the type that gets returned may not be an Object type at all. In OOP languages, there is the concept of polymorphism in which a contract (interface) is established that inheriting classes must follow. Code outside of that inheritance structure deal only with the contract and don’t care about specific child classes of that contract. Since Object in classical languages is the parent of all types, I think what JavaScript tries to do when a primitive type is passed into the Object constructor, is to return the primitive type – in other words, it’s assuming that you really want x-type rather than an Object. (A related topic/metaphor may be boxing/unboxing, but I felt polymorphism was more applicable.)

Finally, an object simply looks like the following:

var obj = {
    anInt: 1,
    aString: "abc",
    anObj: {
        aMethod: function() {
            return "hi";
        }
    }
}
obj.aBool = true;


An object when initialized does not have to be empty ({}), but can contain properties and methods. An object can also be modified after initialization, as with the aBool property added afterward.

Constructor functions look similar to new Object(), but rather than creating the built-in JavaScript Object, it creates a function that returns a custom-made object. Crockford mentions in his book if you are planning on using new like an OOP language, then make sure the name of the function is capitalized to differentiate its use from a normally invoked function (i.e., add() vs. new Add()).

A custom constructor function may look like (examples taken from the book):

var Person = function (name) {
    this.name = name;
    this.say = function () {
        return "I am " + name;
    }
}

Which behaves like:

var Person = function (name) {
    var this = {};
    this.name = name;
    this.say = function () {
        return "I am " + name;
    }
    return this;
}


Except the explicit creation and return of this is hidden away. Another note is this isn’t really the empty object, but rather something like Object.create(Person.prototype), meaning it inherits Person’s prototype similar to creating a new Object inherits the Object’s prototype. A future topic the book addresses later is reusable members, such as the say() method, should go into the prototype (i.e., Person.prototype) to save the overhead of recreating the method each time the custom constructor function is invoked. (I’ll leave a “bookmark” here if/when I review later down the line.)

Custom constructor functions always return an object when invoked with new and implicitly return this unless another object is explicitly returned. If something other than an object is returned, it is ignored and this is returned instead. In my mind, it is like returning from a function early if you provide an object to return like:

var Thing = function() {
    var box = {
        sides: 6,
        material: "cardboard"
    }
    return box;
    return this;
}

Since box is an object, the function ends early returning the box object.

The use of this in custom constructor functions can easily pollute the global namespace if new is not used. Rather than pointing to the variable it is assigned to, when leaving out new, this will point to window. An alternate pattern to make sure the global namespace isn’t polluted is to use that instead of this. The drawback is the link to the object’s prototype is lost. Recall that this = Object.create(Thing.prototype), but that inherits Object.prototype.

Another solution is to ensure this is an instanceof the constructor:

function Thing = function() {
    if (!(this instanceof Thing)) {
        return new Thing();
    }
    this.box = { }
}


Arrays are objects but also its own type, meaning it has its own constructor. Arrays function similarly in JavaScript as in other classical languages, using square bracket notation and 0-indexing for iteration.

Arrays can be initialized two ways:
-Literal: var arr = [];
-Constructor: var arr = new Array()

Passing in a single integer value to the constructor sets the length of the array, not the first value. Whereas, multiple values passed into the constructor will initialize an array with those values. Care must be taken with using the constructor as it will only accept single integer values or multiple values (type does not matter in this second case). It should not be much of a surprise that the literal notation is the preferred use of array initialization.

Since arrays are objects, typeof will return “Object”. To check if an array is an array, you can use isArray() if ECMAScript 5 is supported, otherwise you can define your own, as helpfully provided by the book:

Array.isArray = function (arg) {
    return Object.prototype.toString.call(arg) === "[object Array]";
}

An object will return "[object Object]" instead.
--

JSON is a notation that makes it easier to pass data between the server and browser. I was hesitant at first to really look into JSON, but it's not all that intimidating, especially after working with objects in more depth. JSON formatting resembles JavaScript objects. The only difference is all property names must be in quotes, whereas with objects, property names do not have to be wrapped in quotes if they are also valid identifiers (e.g., name vs. "first name"). For my PHP scripts that output JSON, I will write a sample template of data I want to pass to the client JavaScript and I find that also helped get me more comfortable with using JSON. I'm still no expert, but I'm not feeling like I need a 10-foot pole to touch it with either.

JSON should not be parsed using eval(), but rather with JSON.parse() or libraries that come with a parsing function. The opposite of parsing JSON into JavaScript objects is to turn JS objects into JSON using JSON.stringify() (or a library function equivalent).
--

Regular expressions also have two ways of initialization:
-Literal: var regex = /[a-z]/;
-Constructor: var regex = new RegExp("[a-z]");

Again, the literal is much shorter to type out. Another drawback of the constructor initialization is the need to escape quotes and backslashes, making the literal initialization much simpler and a bit easier to read.

Pattern modifiers (g, m, i) can be used (e.g., var regex = /[a-z]/gmi; or var regex = new RegExp("[a-z]", "gmi")) in any order and combination.
--

Primitive types in JavaScript include number, string, boolean, null, and undefined. The first three types have primitive wrapper objects, allowing for initialization similar to objects, arrays, and regular expressions:

var num = new Number(1);
var str = new String("Foo");
var bool = new Boolean(true);

What basically happens is num, str, and bool are turned into object types with a set of methods specific to the primitive type. However, primitive types initialized literally (e.g., var num = 1) can have a primitive-type method invoked on them, making the initialization of a primitive type via the constructor redundant. This behavior is possible because the primitive types are temporarily converted into an object type to allow the method call to operate on it. However, primitive types cannot take on properties of their own, in which case, using the constructor initializer may be necessary.
--

Errors are something I haven't used very often in JavaScript so this section was interesting to me. Error objects have two properties, name and message. There are multiple error constructors like SyntaxError() and TypeError(). Custom errors can be made simply by creating an object, making sure the properties name and message are present, along with any other properties necessary. Then, just throw the object.
--

This chapter was another overview of JavaScript elements, but it went into a little more detail of the more commonly-used elements like objects and primitives. The main takeaway is literal initializers are your best friend and rarely will you need to use constructor initializers.