wyc
wyc

Reputation: 55273

Why Backbone.js code is preceded by (function($){...?

This is an example of Backbone.js code (taken from this tutorial):

// **This example illustrates the binding of DOM events to View methods.**
//
// _Working example: [2.html](../2.html)._  
// _[Go to Example 3](3.html)_

//
(function($){
  var ListView = Backbone.View.extend({
    el: $('body'), // el attaches to existing element
    // `events`: Where DOM events are bound to View methods. Backbone doesn't have a separate controller to handle such bindings; it all happens in a View.
    events: {
      'click button#add': 'addItem'
    },
    initialize: function(){
      _.bindAll(this, 'render', 'addItem'); // every function that uses 'this' as the current object should be in here

      this.counter = 0; // total number of items added thus far
      this.render();
    },
    // `render()` now introduces a button to add a new list item.
    render: function(){
      $(this.el).append("<button id='add'>Add list item</button>");
      $(this.el).append("<ul></ul>");
    },
    // `addItem()`: Custom function called via `click` event above.
    addItem: function(){
      this.counter++;
      $('ul', this.el).append("<li>hello world"+this.counter+"</li>");
    }
  });

  var listView = new ListView();      
})(jQuery);

I don't understand why it has to be preceded by an (function($){....

Can anyone explain this to me?

Upvotes: 1

Views: 313

Answers (2)

Tomas Aschan
Tomas Aschan

Reputation: 60584

This is common practice when authoring jQuery plugins.

The reason is that you want to avoid conflicts with other libraries that may also use the $ symbol in the global scope. By wrapping your code in a function call that takes one argument (named $) and pass the jQuery object into that function, you ensure that you avoid conflicts.

function($) { // declare an anonymous function that takes an argument $

    // conflict safe code =)

}(jQuery); // pass the argument jQuery to the anonymous function

As nielsbot noted, it might be easier to see what the above code does if you give the function a name:

var executeSafely = function($) {

    // conflict safe code =)

}

executeSafely(jQuery);

I know this is way after the fact, but MikeG just pointed out in a comment on this post that this isn't necessarily a bad thing to do with javascript code in other places as well. I thought I'd expand a little on why:

A case for scoping

Suppose you have two independent javascript modules on your web site. Let's say you've written the code for them in the two js files module-one.js and module-two.js. Normally, you only have one module on a page, so when authoring one of them, you don't care what happens in the other one (you might even have different developers working on the different modules independently of the other).

Then, you decide it would be nice to show both these things on the start page, so you include the following in the head section of the start page html:

<script type="text/javascript" src="module-one.js" />
<script type="text/javascript" src="module-two.js" />

[Cue: Doomsday music!] Everything breaks down! What the heck happened?

You look in the code for the modules, and see the following:

module-one.js:

var state = 0;

function init() {
    ...
}

etc...

module-two.js:

var state = 2;

function init() {
    ...
}

etc ...

What's going on here?

Well, the page loads the two scripts in order - first module-one.js is loaded, and everything is go for the first module; then, module-two.js is loaded, and overrides some of the variables defined in the first module! This is because defining a variable in the global scope in JavaScript, it is implicitly interpreted as defining it on the window object. Thus, if you run the two script files after each other, you, for example, first set window.state = 0, and then window.state = 2. As you see, the modules aren't really independent. When, for example, init() (or, really, window.init()) is called after both scripts are loaded, only the second module is initiated - the first init() function was overwritten (since window can only have one property named init) and doesn't exist anymore.

Scoping to the rescue

To avoid this problem, you should wrap your modules in function calls, just like you did with the jQuery plugin above. However, these function don't need to take any arguments:

module-one.js

(function() {
    // code for module one here
})();

module-two.js

(function() {
    // code for module two here
})();

Now, since the two modules are defined inside separate functions, all variables are scoped to live only within those functions. If you're unsure how your JavaScript code will be used, wrapping it in a function call like this is good practice to avoid conflicts. And since it can be hard to remember good practices if you don't follow them all the time, following this one all the time really doesn't hurt anyone =)

Upvotes: 7

nielsbot
nielsbot

Reputation: 16022

It's to guarantee that $ is assigned to the jQuery object within the defined function. They're basically doing this:

var theFunction = function($){...code...};
theFunction(jQuery);

Do you see it?

Upvotes: 0

Related Questions