26

In Javascript there are a few clearly prominent techniques for create and manage classes/namespaces in javascript.

I am curious what situations warrant using one technique vs. the other. I want to pick one and stick with it moving forward.

I write enterprise code that is maintained and shared across multiple teams, and I want to know what is the best practice when writing maintainable javascript ?

I tend to prefer Self-Executing Anonymous Functions however I am curious what the community vote is on these techniques.

Prototype :

function obj()
{
}

obj.prototype.test = function() { alert('Hello?'); };
var obj2 = new obj();
obj2.test();

Self-Closing Anonymous Function :

//Self-Executing Anonymous Function 
(function( skillet, $, undefined ) {
    //Private Property
    var isHot = true;

    //Public Property
    skillet.ingredient = "Bacon Strips";

    //Public Method
    skillet.fry = function() {
        var oliveOil;

        addItem( "\t\n Butter \n\t" );
        addItem( oliveOil );
        console.log( "Frying " + skillet.ingredient );
    };

    //Private Method
    function addItem( item ) {
        if ( item !== undefined ) {
            console.log( "Adding " + $.trim(item) );
        }
    }     
}( window.skillet = window.skillet || {}, jQuery ));   
//Public Properties      
console.log( skillet.ingredient ); //Bacon Strips  

//Public Methods 
skillet.fry(); //Adding Butter & Fraying Bacon Strips 

//Adding a Public Property 
skillet.quantity = "12"; console.log( skillet.quantity ); //12   

//Adding New Functionality to the Skillet 
(function( skillet, $, undefined ) {
    //Private Property
    var amountOfGrease = "1 Cup";

    //Public Method
    skillet.toString = function() {
        console.log( skillet.quantity + " " + 
                     skillet.ingredient + " & " + 
                     amountOfGrease + " of Grease" );
        console.log( isHot ? "Hot" : "Cold" );
     };     

}( window.skillet = window.skillet || {}, jQuery ));
//end of skillet definition


try {
    //12 Bacon Strips & 1 Cup of Grease
    skillet.toString(); //Throws Exception 
} catch( e ) {
    console.log( e.message ); //isHot is not defined
}

I feel that I should mention that the Self-Executing Anonymous Function is the pattern used by the jQuery team.

Update When I asked this question I didn't truly see the importance of what I was trying to understand. The real issue at hand is whether or not to use new to create instances of your objects or to use patterns which do not require constructors/use of the new keyword.

I added my own answer, because in my opinion we should make use of patterns which don't use the new keyword.

For more information please see my answer.

13
  • 1
    can you give short examples of the two techniques you are describing?
    – Hey
    Jan 6, 2012 at 3:48
  • Don't underestimate prototype because of my simple sample.
    – Robotsushi
    Jan 6, 2012 at 3:59
  • 1
    it's not executing itself =/
    – Hey
    Jan 6, 2012 at 4:06
  • 2
    i don't see any parentheses to close the expression or call it...
    – Hey
    Jan 6, 2012 at 4:18
  • 1
    (+1) Namespaces are overlooked for many developers.
    – umlcat
    Feb 3, 2012 at 19:57

7 Answers 7

22

Self executing anonymous functions are used to automate script execution without hooking into external events (i.e. window.onload).

In this example it is used to form the classic Module pattern, the primary purpose of which is to introduce a namespace into the global environment, and provide encapsulation for any internal properties that are not "exported" or attached to the namespace.

Modifying an objects prototype, on the other hand, is used to establish inheritance (or extend natives). This pattern is used to produce 1:n objects with common methods or properties.

You should not choose one pattern in preference to the other, since they perform different tasks. In terms of namespacing, the Self Executing Function is an appropriate choice.

2
  • 8
    Note that "self executing anonymous functions" are commonly known as immediately-invoked function expressions (IIFE).
    – voithos
    Jan 23, 2014 at 0:46
  • I avoid them and to be honest I don't get the love with IIFEs. They are a messy to debug and break code outline in Eclipse. If you need a namespace stick it on an object, if you need to execute it just call it, and encapsulation doesn't really gain me anything. Feb 4, 2015 at 4:43
4

Here's the pattern that I just began using (have been using variations of it up until yesterday):

function MyClass() {
    // attributes
    var privateVar = null;

    // function implementations
    function myPublicFunction() {
    }

    function myPrivateFunction() {
    }

    // public declarations
    this.myPublicFunction = myPublicFunction;
}

MyClass.prototype = new ParentClass(); // if required

A few thoughts on this:

  1. You shouldn't get any (anonymous) traces in your debugger stack traces as everything's named (no anonymous functions).
  2. It's the cleanest pattern that I've seen yet
  3. You're able to easily group up your exposed API without having their implementations coupled to the declaration (meaning someone can easily grok your public class interface without having to scroll)

The only time that I'd use prototype anymore really is to define inheritance.

6
  • 5
    There are a few problems with this. A new function object is created for each "method" with each invocation of the constructor. Also, calling a constructor to get a copy of prototype object for inheritance is frowned on. Use Object.create(ParentClass.prototype), or a shim for Object.create like function clone(obj){return this typeof 'clone' ? this : new clone(clone.prototype=obj)}
    – Hey
    Jan 6, 2012 at 5:04
  • @GGG: Yes, you're correct with your first point. I'd say (and should have mentioned in my post) that each specific use case of an implementation should be thought through. My issue with prototype method as you suggest is (unless there's a method that I'm unfamiliar with, which may be the case) that you lose the ability to encapsulate attributes, meaning everything's open as public (which isn't the end of the world, just a personal preference). Jan 7, 2012 at 22:14
  • Also, after viewing the following work done on jsperf (jsperf.com/object-create-vs-constructor-vs-object-literal/12), I would take the performance increase over memory cost of additional copies almost any day (again, very subjective to the specific use case). Jan 7, 2012 at 22:16
  • Now, having said all that, I'm only partway through ECMA-262, so there may be a bunch of stuff that I'm not seeing.. Also, I don't take Crockford's word as gospel.. Yes, he's one of the experts in the field (one of the foremost of course), but it doesn't always make him 100% right at all times. There are other experts out there (me not being one of them ;)) who have contradictory opinions with compelling arguments. Jan 7, 2012 at 22:18
  • 2
    you might be interested in this thing I'm working on.
    – Hey
    Jan 7, 2012 at 22:43
3

I use prototypes because they are cleaner and follow standard inheritance patterns. Self-invoking functions are great for browser development or a situation where you don't know where the code is being executed, but otherwise it's just noise.

Example:

var me;

function MyObject () {
    this.name = "Something";
}

MyObject.prototype.speak = function speak () {
    return "Hello, my name is " + this.name;
};

me = new MyObject();
me.name = "Joshua";
alert(me.speak());
1
  • 2
    Self executing anonymous functions are very useful for allowing you have private functions accessible to a class.
    – Zee
    Jan 7, 2012 at 20:28
1

I'd go with the self-executing function, but with a slight difference:

MyClass = (function() {
     var methodOne = function () {};
     var methodTwo = function () {};
     var privateProperty = "private";
     var publicProperty = "public";

     return function MyClass() {
         this.methodOne = methodOne;
         this.methodTwo = methodTwo;
         this.publicProperty = publicProperty;
     };
})();

If find this approach much cleaner, as I separate the returned global variable from any input parameters (such as jQuery) (the way you wrote it is equivalent to returning void and using a ref parameter in C#, which I find a bit off, or passing in a pointer to a pointer and re-assigning it in C++). If I were then going to attach additional methods or properties to the class I would use prototypal inheritance (example with jQuery's $.extend method, but it's easy enough to roll your own extend()):

var additionalClassMethods = (function () {
    var additionalMethod = function () { alert('Test Method'); };
    return { additionalMethod: additionalMethod };
})();

$.extend(MyClass.prototype, additionalClassMethods);

var m = new MyClass();
m.additionalMethod(); // Pops out "Test Method"

This way you have a clear distinction between the added methods and the original ones.

1
  • 1
    Am I the only one who thinks using NFEs like this is a bad idea?
    – Hey
    Jan 6, 2012 at 22:34
1

Live Example

(function _anonymouswrapper(undefined) {

    var Skillet = {
        constructor: function (options) {
            options && extend(this, options);
            return this; 
        },
        ingredient: "Bacon Strips",
        _isHot: true,
        fry: function fry(oliveOil) {
            this._addItem("\t\n Butter \n\t");
            this._addItem(oliveOil);
            this._addItem(this.ingredient);
            console.log("Frying " + this.ingredient);
        },
        _addItem: function addItem(item) {
            console.log("Adding " + item.toString().trim());
        }
    };

    var skillet = Object.create(Skillet).constructor();

    console.log(skillet.ingredient);
    skillet.fry("olive oil");

    var PrintableSkillet = extend(Object.create(Skillet), {
        constructor: function constructor(options) {
            options && extend(this, options);
            return this;
        },
        _amountOfGrease: "1 Cup",
        quantity: 12,
        toString: function toString() {
            console.log(this.quantity + " " +
                        this.ingredient + " & " +
                        this._amountOfGrease + " of Grease");
            console.log(this._isHot ? "Hot" : "Cold");
        }
    });

    var skillet = Object.create(PrintableSkillet).constructor();

    skillet.toString();

    function extend(target, source) {
        Object.getOwnPropertyNames(source).forEach(function (name) {
            var pd = Object.getOwnPropertyDescriptor(source, name);
            Object.defineProperty(target, name, pd);
        });
        return target;
    }
}());

You can use a IIFE to emulate "module scope" around your code. Then you can just use objects as you normally do.

Don't "emulate" private state using closures as that has a large memory penalty.

If your writing an enterprise application and want to keep your memory usage under 1GB avoid unnecessarily using closures to store state.

10
  • You've got a couple of typos in the code mate. I'm not positive about your assertion of closures automatically causing excessive memory usage either, I think it depends on how heavily you use them and how well you're dealing with scoping issues (mixing things from inside a closure with things from outside is generally bad, for example (your usage of the global console is a good example of this, the above code would be much more efficient if you passed in console as a variable)).
    – Ed James
    Jan 6, 2012 at 11:59
  • @EdWoodcock I figured the code was buggy, just refactored and fixed it.
    – Raynos
    Jan 6, 2012 at 12:01
  • @EdWoodcock the efficiency difference between local console and global console is a micro optimisation. It is worth doing so you can minimize console but that's a different matter
    – Raynos
    Jan 6, 2012 at 12:04
  • @EdWoodcock closures are slow if your duplicating objects in them. What's slow is creating functions inside functions when it's not needed. closures also have small memory overhead for storing state in comparison to storing state on objects directly
    – Raynos
    Jan 6, 2012 at 12:05
  • Yeah, just wanted to point it out since your answer is a reasonable way of going about things (albeit not the way I'd choose to use). (I'd have done an edit but I'm still not sure about the etiquette of those on this particular SE site).
    – Ed James
    Jan 6, 2012 at 12:05
0

Update I now have a much better understanding of javascript and feel I can properly address the question. I think it was a poorly worded, but very important javascript topic to address.

The Self Executing Anonymous Function pattern is not one which requires use of the new keyword if you avoid the use of this outside of functions. I agree with the idea that using new is an old technique and we should instead strive to use patterns that avoid the use of new.

The Self Executing Anonymous Function meets this criteria.

The answer to this question is subjective, because there are so many coding styles in javascript. However based on my research and experience I would recommend choosing to use the Self Executing Anonymous Function to define your API's and avoid the use of new whenever possible.

1
  • 2
    What is bad about the new keyword? I'm curious.
    – Ally
    Jan 23, 2014 at 9:31
0

Here is how I would go about this IIFE SelfExecutingFunction to extend the Myclass with Myclass.anotherFunction();

MyClass = (function() {
     var methodOne = function () {};
     var methodTwo = function () {};
     var privateProperty = "private";
     var publicProperty = "public";

    //Returning the anonymous object {} all the methods and properties are reflected in Myclass constructor that you want public those no included became hidden through closure; 
     return {
         methodOne = methodOne;
         methodTwo = methodTwo;
         publicProperty = publicProperty;
     };
})();

@@@@@@@@@@@@@@@@@@@@@@@@
//then define another IIFE SEF to add var function=anothermethod(){};
(function(obj){
return obj.anotherfunction=function(){console.log("Added to Myclass.anotherfunction");};
})(Myclass);

//the last bit : (function(obj){})(Myclass); obj === Myclass obj is an alias to pass the Myclass to IIFE

var myclass = new Myclass();
myclass.anotherfunction(); //"Added to Myclass.anotherfunction"
1
  • 1
    Programmers is tour conceptual questions answers are expected to explain things. Throwing code dumps instead of explanation is like copying code from IDE to whiteboard: it may look familiar and even sometimes be understandable, but it feels weird... just weird. Whiteboard doesn't have compiler
    – gnat
    Jan 23, 2014 at 2:54

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.