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?
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 thejQueryobject into that function, you ensure that you avoid conflicts.As nielsbot noted, it might be easier to see what the above code does if you give the function a name:
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.jsandmodule-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:
[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:
module-two.js:
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
windowobject. Thus, if you run the two script files after each other, you, for example, first setwindow.state = 0, and thenwindow.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 firstinit()function was overwritten (sincewindowcan only have one property namedinit) 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
module-two.js
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 =)