2013-11-08

Immediately invoked constructors and object literals

By now, you are probably familiar with immediately invoked function expressions (IIFEs, [1]). This blog post looks at immediately invoked constructors and immediately invoked object literals.

Immediately invoked constructors

Andrea Giammarchi (@WebReflection) recently reminded us that you can immediately invoke constructors. That is useful for setting up plain objects. Let’s look at a (slightly contrived) example:
    var obj = new function () {  // open IIC
        var uid = computeUID();
        this.first = 'Jane';
        this.last = 'Doe';
        this.uid = uid;
    }();  // close IIC
The immediately invoked constructor provides you with a private scope, in which the variable uid lives. You can then use this to set up the instance that has been created by new. Additionally, new returns that instance for you. You can save a few characters by omitting the parentheses at the end:
    var obj = new function () {  // open IIC
        ...
    };  // close IIC
The above code works, because parentheses are optional if you call a constructor with zero arguments. That is, the following two statements are equivalent.
    var d = new Date();
    var d = new Date;
However, I prefer the first variant; I find it more explicit.

Obviously, an IIFE is always an alternative to an immediately invoked constructor. It has two advantages: The code should look more familiar and you can use an object literal.

    var obj = function () {
        var uid = computeUID();
        return {
            first: 'Jane',
            last: 'Doe',
            uid: uid
        };
    }();

Immediately invoked object literals

You can immediately invoke a method on an object literal:
    ({
        errorCount: 0,
        step1: function () {
            ...
        },
        step2: function () {
            ...
        },
        logError(message) {
            console.log(message);
            this.errorCount++;
        },
        main: function () {
            this.step1();
            this.step2();
            console.log('Errors:'+this.errorCount);
        }
    }.main());
Note that we can’t start the first line with a brace, because then the object literal would be interpreted as a code block by JavaScript [2].

Depending on your taste, you may prefer an IIFE:

    (function () {
        var errorCount = 0;

        function step1() {
            ...
        }

        function step2() {
            ...
        }

        function logError(message) {
            console.log(message);
            errorCount++;
        }

        // main
        step1();
        step2();
        console.log('Errors:'+errorCount);
    }());
Obviously, you could also turn the lines of main into a function and invoke that function last inside the IIFE.

References

  1. JavaScript variable scoping and its pitfalls
  2. Expressions versus statements in JavaScript

No comments: