5

I came across the following pattern when looking through the SlickGrid source code:

(function ($) {
  var SlickEditor = {

    TextCellEditor: function (args) {
      ...
    },

    LongTextCellEditor: function (args) {
      ...
    }
  };

  $.extend(window, SlickEditor);

})(jQuery);

If I understand this correctly, it is using immediate invocation to define various function objects and then merge them into the global namespace.

So I could just define my functions globally like this and it would have the same effect, right?

function TextCellEditor (args) {
  ...
}

function LongTextCellEditor (args) {
  ...
}

The only difference I can see is that in the first version, I can use the $ shorthand to refer to the jQuery object. Apart from that the result would be identical in both cases.

I would like to know if I am missing something. Maybe there is another good reason for doing things this way?

UPDATE: Please note, I realise that using this immediate invocation pattern allows for the use of private variables declared in the anonymous function. But there aren't any variables declared in this case and the functions are being injected into the global scope anyway. So I'd still like to know if there's any real difference.

Some answers pointed out that referencing local variables is much faster than referencing global variables. Does this still hold true if I reference $from within the TextCellEditor() constructor. $ is not really local to TextCellEditor() since it is defined in the scope of the outer anonymous function.

All comments appreciated.

njr101
  • 9,499
  • 7
  • 39
  • 56
  • ... The example shown injects a single variable into global scope. You inject multiple functions into global scope. There's a massive difference between one global variable and many global variables – Raynos Dec 13 '11 at 09:39
  • @Raynos: Both examples inject the same functions into global scope. the `$.extend()` call extends the window object with all the properties of `SlickEditor` (in this case the two constructor functions). That's the point of my question - what's the difference? – njr101 Dec 13 '11 at 12:55
  • oh wait, I didn't realise the SlickEditor author was an idiot and injected all the functions into global scope. That's an anti pattern, both code samples are bad practice. – Raynos Dec 13 '11 at 13:00

4 Answers4

3

The difference is that you are creating a local scope for private variables when you use a self invoking function like the one you have shown.

That type of self invoking function is usually called a closure and is the basis of many javascript patterns like the module pattern: http://www.adequatelygood.com/2010/3/JavaScript-Module-Pattern-In-Depth

You can read more about javascript scoping here: http://www.adequatelygood.com/2010/2/JavaScript-Scoping-and-Hoisting

The reason for passing the jQuery vairable in is 2 fold:

1: it's more convinient to call it via $ and since it was passed in as a local variable we can be sure that $ isn't something else

2: it's faster - local variables are much faster to access and work with than global variables

As an example take a look at the following chunk of code:

var public_and_global=true;

(function(){
  var private_and_local = true;

  function local_func() {
   //can use private_and_local as well as public_and_global
  }

})();

function global_func() {
   //can only use public_and_global
}
Martin Jespersen
  • 25,743
  • 8
  • 56
  • 68
  • There are no "private" variables – Raynos Dec 12 '11 at 14:23
  • Thanks Martin. I understand the scoping/closure issue. But since there are no variables in the anonymous function I thought this would mean that the net result would be the same in both my examples. I wasn't aware of the performance difference. Does the performance benefit apply to using `$` within the TextCellEditor constructor? I'm not sure because `$` is not really local to that function, but local to the anonymous function in the outer scope. – njr101 Dec 12 '11 at 16:46
  • You are right, in your exact example the net result is very close to being the same, except for the two functions in the first example being namespaced inside the `SlickEditor` namespace. Weather or not their is a performance difference in the exact scenario is something i will leave to your to test :) – Martin Jespersen Dec 13 '11 at 06:33
  • @Raynos: Thanks for being constructive – Martin Jespersen Dec 13 '11 at 06:35
  • @MartinJespersen sorry but phrases like `private_and_local` make it seem like there's an actual difference between "private" and local when there's not. It's a poor choice of wording. – Raynos Dec 13 '11 at 10:04
1

Everyone wraps their entire code in an IIFE.

This is because everyone uses local variables and no-one uses global variables.

If your modular architecture technique happens to be "Inject modules into global scope" then you will inject modules into global scope from your IIFE.

Raynos
  • 166,823
  • 56
  • 351
  • 396
0

Yes, it would have the same effect, in most cases. But this way is nice because you can always use the shorthand but also because there will be no variables cluttering the global namespace. Say I have this extension, to generate unique ids:

var UID = (new Date).getTime();
$.uniqueID = function() { return (UID++).toString(16); }

This would just work, but if I set UID later, probably in another script, this function will not work anymore. And well, you can never be too sure about the availability of $ which is a good reason, too.

Variables defined inside a function will not exist in the global namespace.

goto-bus-stop
  • 11,655
  • 2
  • 24
  • 31
0

Definitely, what Martin said. Also:

So I could just define my functions globally like this and it would have the same effect, right?

No. Those functions are not ending up in the global name space. They are being created in a local scope, and then references to them are given to jQuery. Nothing is added to the global scope.

Although the snippet you showed does not demonstrate this, it is possible to define some private data, besides the functions, inside that scope, for example, fixed strings, or lookup tables, or whatever auxiliary data those methods might need, and the functions will have access to that data, and yet that data will not be accessible to any other code (analogous to "private" in OO), nor will that data pollute the global name space.

smendola
  • 2,273
  • 1
  • 15
  • 14
  • I don't understand this. Surely the line `$.extend(window, SlickEditor);` will extend the global object (in the case of a browser it is the window object). Those functions are going to be available to any line of code, with no dependence on jQuery. – njr101 Dec 12 '11 at 16:39