Does this way of defining JS objects have any purpose?

JavascriptJavascript Objects

Javascript Problem Overview


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!

Javascript Solutions


Solution 1 - Javascript

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

Solution 2 - Javascript

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

Solution 3 - Javascript

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.

Solution 4 - Javascript

  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)

Solution 5 - Javascript

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.

Solution 6 - Javascript

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.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionSebasti&#225;n VansteenkisteView Question on Stackoverflow
Solution 1 - JavascriptJuan MendesView Answer on Stackoverflow
Solution 2 - JavascriptJonathan CroweView Answer on Stackoverflow
Solution 3 - Javascriptuser663031View Answer on Stackoverflow
Solution 4 - JavascriptfrogattoView Answer on Stackoverflow
Solution 5 - JavascriptMateenView Answer on Stackoverflow
Solution 6 - JavascriptBarmarView Answer on Stackoverflow