38

I've read that rather than simply writing a bunch of functions, I should use an object literal.

What are the advantages of object literal, with examples?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Jourkey
  • 33,710
  • 23
  • 62
  • 78

4 Answers4

66

As Russ Cam said, you avoid polluting the global namespace, which is very important in these days of combining scripts from multiple locations (TinyMCE, etc.).

As Alex Sexton said, it makes for good code organisation as well.

If you're using this technique, I'd suggest using the module pattern. This still uses object literals, but as the return value from a scoping function:

var MyThingy = (function() {

    function doSomethingCool() {
        ...
    }

    function internalSomething() {
        ....
    }

    function anotherNiftyThing() {
        // Note that within the scoping function, functions can
        // call each other direct.
        doSomethingCool();
        internalSomething();
    }

    return {
        doSomethingCool: doSomethingCool,
        anotherNiftyThing: anotherNiftyThing
    };
})();

External use:

MyThingy.doSomethingCool();

The scoping function is wrapped around all of your functions, and then you call it immediately and store its return value. Advantages:

  • Functions are declared normally and therefore have names. (Whereas with the {name: function() { ... }} format, all of your functions are anonymous, even though the properties referencing them have names.) Names help tools help you, from showing call stacks in a debugger, to telling you what function threw an exception. (2015 Update: The latest JavaScript specification, ECMAScript 6th edition, defines a large number of ways the JavaScript engine must infer a function's name. One of those is when the function is assigned to a property as in our {name: function() { ... }} example. So as engines implement ES6, this reason will go away.)
  • Gives you the freedom of having private functions only used by your module (such as my internalSomething above). No other code on the page can call those functions; they're truly private. Only the ones you export at the end, in the return statement, are visible outside the scoping function.
  • Makes it easy to return different functions depending on environment, if the implementation just changes completely (such as IE-vs-W3C stuff, or SVG vs. Canvas, etc.).

Example of returning different functions:

var MyUtils = (function() {
    function hookViaAttach(element, eventName, handler) {
        element.attachEvent('on' + eventName, handler);
    }

    function hookViaListener(element, eventName, handler) {
        element.addEventListener(eventName, handler, false);
    }

    return {
        hook: window.attachEvent ? hookViaAttach : hookViaListener
    };
})();

MyUtils.hook(document.getElementById('foo'), 'click', /* handler goes here */);
T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • 2
    When you instantiate a function in the "anonymous" way, you can still give it a name (var x = function x() { ... }). When you do that, the name is bound such that it's available for recursive references within the function. – Pointy Oct 21 '09 at 13:39
  • 1
    @Pointy: You can't do that (use a function name within an assignment) cross-browser, it doesn't work correctly on either IE or Safari; details: http://yura.thinkweb2.com/named-function-expressions/ And you don't need to, the function's proper name (the `foo` in `function foo`) is in-scope in the entire scope where it's declared, including within the function itself, so `foo` can call itself via the symbol `foo`, no need to assign the function reference to anything (at that point). – T.J. Crowder Oct 21 '09 at 15:17
  • (Continuing) Granted it would be *nice* to be able to use both assignment and proper name at the same time because it would make it easier to export functions from the scoping function. The spec certainly allows it, but sadly, practicalities (implementation bugs) enter into it. – T.J. Crowder Oct 21 '09 at 15:18
15

Using an object literal (a.k.a. object literal pattern) will not pollute the global namespace as severely as using many functions declared globally will, and also helps to organise code in a logical fashion

For example, this object literal

var obj = {
              find : function(elem) { /* find code */ },
              doSomething: function() { /* doSomething code */ },
              doSomethingElse: function() { /* doSomethingElse code */ }
          }

compared to

function find(elem) { /* find code */ },
function doSomething() { /* doSomething code */ },
function doSomethingElse() { /* doSomethingElse code */ }

will create only one property on the global object compared to three. You can then easily use the functions like so

obj.doSomething();
Russ Cam
  • 124,184
  • 33
  • 204
  • 266
  • 2
    you could just write many function in one normal function and not pollute your code. object literal doesn't give any added value. I myself use the prototype method.. – vsync Nov 30 '09 at 07:26
10

Rebecca Murphey did a talk on Object Literals at this year's jQuery Conference. One of the best reasons to use them is simply good code organization.

Here is Rebecca's write up on the Object Literal Pattern : http://rmurphey.com/blog/2009/10/15/using-objects-to-organize-your-code/

reevesy
  • 3,452
  • 1
  • 26
  • 23
Alex Sexton
  • 10,401
  • 2
  • 29
  • 41
  • 2
    Another great article on object literals: http://www.wait-till-i.com/2006/02/16/show-love-to-the-object-literal/ – Alex Sexton Oct 21 '09 at 11:13
2

I’ve always used object literals because they are a clear way to organise code. Which is why I don't like prototype; it's too messy.

Functions don't pollute the name space as someone mentioned in previous answers any more than object literals.

You could easily write a literal like

var obj = {}
var find = function(elem) { /* Find code */ },
var doSomething = function() { /* doSomething code */ },
var doSomethingElse = function() { /* doSomethingElse code */ }

Which would pollute by creating lots of global objects, the same as the functions. Similarly you could do:

(function() {
    function find(elem) { /* Find code */ },
    function doSomething() { /* doSomething code */ },
    function doSomethingElse() { /* doSomethingElse code */ }
})();

Which would not create those global objects (everything is an object in JavaScript).

that way you still don't create loads of global objects.

To my mind object literals have two advantages. One they are used by many plugins such as jQuery so people are familier and they are easy to read. Making them easy to pass through data into a plugin. It's easy to create both public and private methods....

They can be slow though as every time you create an instance of the object all it's methods are duplicated. It's my understanding that that isn't the case with prototype as you have one copy of the methods and new ojects simply reference the prototype.

I could be wrong of course...

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
  • 2
    Object literals are good for namespacing and singletons, when you create multiple instances of an object with shared behavior then it would be better to use constructor functions. I have not found a use case where consuming more cpu and memory by simulating privates out ways using `_myPrivate` for privates instead but would be happy if someone can provide me with one. More on prototype, inheritance, mix ins here: http://stackoverflow.com/a/16063711/1641941 – HMR Nov 09 '13 at 03:24