86

I'm maintaining some legacy code and I've noticed that the following pattern for defining objects is used:

var MyObject = {};

(function (root) {

    root.myFunction = function (foo) {
        //do something
    };

})(MyObject);

Is there any purpose to this? Is it equivalent to just doing the following?

var MyObject = {

    myFunction : function (foo) {
        //do something
    };

};

I'm not about to embark in a holy quest to refactor the whole codebase to my likings, but I'd really like to understand the reason behind that roundabout way of defining objects.

Thanks!

Sebastián Vansteenkiste
  • 2,234
  • 1
  • 19
  • 29
  • 1
    In your exact example there is no difference. If you expand it, there may be a difference but then there will also be different approaches that come in to play as well. – Travis J Nov 06 '14 at 20:11
  • It makes no difference, objects are passed as a copy of a reference so to speak, so even when defining the myFunction inside the IIFE, it's still accessible outside it. – adeneo Nov 06 '14 at 20:18
  • 1
    @adeneo Not for this example, by `myFunction` could use some variables defined outside of itself that would not be accessible from the outside. [See my answer](http://stackoverflow.com/a/26788447/227299) – Ruan Mendes Nov 06 '14 at 20:57
  • 2
    possible duplicate of [What is this JavaScript pattern called and why is it used?](http://stackoverflow.com/q/26092101/1048572) (not sure whether I should close). See also [JavaScript Namespace Declaration](http://stackoverflow.com/a/2504761/1048572) or [this one](http://stackoverflow.com/q/881515/1048572). – Bergi Nov 07 '14 at 01:04
  • 1
    @Bergi also similar to [What is the functional difference between these two different Module pattern syntaxes](http://stackoverflow.com/questions/24977784/what-is-the-functional-difference-between-these-two-different-module-pattern-syn) – Qantas 94 Heavy Nov 07 '14 at 12:51
  • Whoa, I didn't get any email notifications about this question, sorry for the late reply. I'm marking @juan-mendes answer as the correct one, but I want to thank everyone for chipping in :D Bottom line is: the code a found is a "bad example" because it does not use any private methods or variables, it's just making things harder to read without making any real use of closures. – Sebastián Vansteenkiste Nov 11 '14 at 19:50

6 Answers6

116

It's called the module pattern http://toddmotto.com/mastering-the-module-pattern/

The main reason is for you to create truly private methods and variables. In your case, it's not meaningful because it's not hiding any implementation details.

Here's an example where it makes sense to use the module pattern.

var MyNameSpace = {};

(function(ns){
    // The value variable is hidden from the outside world
    var value = 0;

    // So is this function
    function adder(num) {
       return num + 1;
    }

    ns.getNext = function () {
       return value = adder(value);
    }
})(MyNameSpace);

var id = MyNameSpace.getNext(); // 1
var otherId = MyNameSpace.getNext(); // 2
var otherId = MyNameSpace.getNext(); // 3

Whereas if you just used a straight object, adder and value would become public

var MyNameSpace = {
    value: 0,
    adder: function(num) {
       return num + 1;
    },
    getNext: function() {
       return this.value = this.adder(this.value);
    }
}

And you could break it by doing stuff like

MyNameSpace.getNext(); // 1
MyNameSpace.value = 0;
MyNameSpace.getNext(); // 1 again
delete MyNameSpace.adder;
MyNameSpace.getNext(); // error undefined is not a function

But with the module version

MyNameSpace.getNext(); // 1
 // Is not affecting the internal value, it's creating a new property
MyNameSpace.value = 0;
MyNameSpace.getNext(); // 2, yessss
// Is not deleting anything
delete MyNameSpace.adder;
MyNameSpace.getNext(); // no problemo, outputs 3
Ruan Mendes
  • 90,375
  • 31
  • 153
  • 217
22

The purpose is to limit accessibility of functions within the closure to help prevent other scripts from executing code on it. By wrapping it around a closure you are redefining the scope of execution for all code inside the closure and effectively creating a private scope. See this article for more info:

http://lupomontero.com/using-javascript-closures-to-create-private-scopes/

From the article:

One of the best known problems in JavaScript is its dependance on a global scope, which basically means that any variables you declare outside of a function live in the same name space: the ominous window object. Because of the nature of web pages, many scripts from different sources can (and will) run on the same page sharing a common global scope and this can be a really really bad thing as it can lead to name collisions (variables with the same names being overwritten) and security issues. To minimise the problem we can use JavaScript’s powerful closures to create private scopes where we can be sure our variables are invisible to other scripts on the page.



Code:

var MyObject = {};

(function (root) {
    function myPrivateFunction() {
       return "I can only be called from within the closure";
    }

    root.myFunction = function (foo) {
        //do something
    };    

    myPrivateFunction(); // returns "I can only be called from within the closure"

})(MyObject);


myPrivateFunction(); // throws error - undefined is not a function
Jonathan Crowe
  • 5,793
  • 1
  • 18
  • 28
  • 1
    `myFunction` isn't in the global scope in the second version. The purpose is actually to provide a scope where internal auxiliary functions could be defined. – Barmar Nov 06 '14 at 20:11
  • `myFunction` is in the global scope because it is defined within the global object `myObject`. In the second version any other code in the application could execute `myFunction`. In the first version only code within the closure has access to `myFunction` – Jonathan Crowe Nov 06 '14 at 20:13
  • No, `myFunction` can only be executed as `MyObject.myFunction()`, the same as the first version. – Barmar Nov 06 '14 at 20:14
  • @JonathanCrowe The OP's example is not a good example, it's exposing everything inside the module, so yes, it is becoming accessible outside. See my answer for a useful module case – Ruan Mendes Nov 06 '14 at 20:14
  • @JuanMendes good point, OP's example is not a great use of the module pattern – Jonathan Crowe Nov 06 '14 at 20:15
6

In the particular case that you show, there is no meaningful difference, in terms of functionality or visibility.

It's likely that the original coder adopted this approach as a sort of template allowing him to define private variables that could be used in the definition of things like myFunction:

var MyObject = {};
(function(root) {
    var seconds_per_day = 24 * 60 * 60;   // <-- private variable
    root.myFunction = function(foo) {
        return seconds_per_day;
    };
})(MyObject);

This avoids calculating seconds_per_day each time the function is called, while also keeping it from polluting the global scope.

However, there's nothing essentially different from that and just saying

var MyObject = function() {
    var seconds_per_day = 24 * 60 * 60;
    return {
        myFunction: function(foo) {
            return seconds_per_day;
        }
    };
}();

The original coder may have preferred to be able to add functions to the object using the declarative syntax of root.myFunction = function, rather than the object/property syntax of myFunction: function. But that difference is mainly a matter of preference.

However, the structure taken by the original coder has the advantage that properties/methods can be easily added elsewhere in the code:

var MyObject = {};
(function(root) {
    var seconds_per_day = 24 * 60 * 60;
    root.myFunction = function(foo) {
        return seconds_per_day;
    };
})(MyObject);

(function(root) {
    var another_private_variable = Math.pi;
    root.myFunction2 = function(bar) { };
})(MyObject);

Bottom line, there is no need to adopt this approach if you don't need to, but there is also no need to change it, since it works perfectly well and actually has some advantages.

6
  1. First pattern can be used as a module which takes an object and returns that object with some modifications. In other words, you can define such modules as follows.

    var module = function (root) {
        root.myFunction = function (foo) {
            //do something
        };
    }
    

    And use it like:

    var obj = {};
    module(obj);
    

    So an advantage could be the re-usability of this module for later uses.


  1. In the first pattern, you can define a private scope to store your private stuff such as private properties and methods. For example, consider this snippet:

    (function (root) {
    
        // A private property
        var factor = 3;
    
        root.multiply = function (foo) {
            return foo * factor;
        };
    })(MyObject);
    

  1. This pattern can be used to add a method or property to all types of objects such as arrays, object literals, functions.

    function sum(a, b) {
        return a + b;
    }
    
    (function (root) {
        // A private property
        var factor = 3;
        root.multiply = function (foo) {
            return foo * factor;
        };
    })(sum);
    
    console.log(sum(1, 2)); // 3
    console.log(sum.multiply(4)); // 12
    

In my opinion the main advantage could be the second one (creating a private scope)

frogatto
  • 28,539
  • 11
  • 83
  • 129
6

advantages:

  1. maintains variables in private scope.

  2. you can extend the functionality of the existing object.

  3. performance is increased.

i think the above three simple points are just enough to follow those rules. And to keep it simple its nothing but writing inner functions.

Mateen
  • 1,631
  • 1
  • 23
  • 27
5

This pattern provides a scope in which you can define helper functions that are not visible in the global scope:

(function (root) {

    function doFoo() { ... };

    root.myFunction = function (foo) {
        //do something
        doFoo();
        //do something else
    };

})(MyObject);

doFoo is local to the anonymous function, it can't be referenced from outside.

Barmar
  • 741,623
  • 53
  • 500
  • 612