for the longest time I was writing all my code inside like this ...
$(document).ready(function(){
$('.show_module').click(function(){
});
...
});
putting all sorts of click handlers in there. But recently I was introduced to a new way of doing things and I wanted to get a feel for if its a smart way of going about it.
the idea is to have all the handlers in related functions and then have minimal code in document.ready above.
So for example ...
$(document).ready(function(){
page_handler(); // other functions follow
});
function page_handler(){
$('.show_module').click(function(){
});
...
}
This seems to allow organization of related handlers in functions and use document.ready as more of an initializer.
I know in JavaScript functions and variables are 'hoisted' before code starts executing so
do_something();
function do_something(){
}
works for this reason, since the function is ready to use before do_something() is actually called, even though it appears before the actual function definition.
I was wondering if the same thing happens here and how 'good' this idea/way of doing things is.
That will expose all your handlers to the global (window) scope, which may lead to clashes.
I prefer to do this...
(function($) {
// Anything you do in here won't be attached to window.
var a;
// If you must have something global, set it explicitly
window.doSomething = function() { ... }
// We can also use $ for jQuery here, even if we have used jQuery.noConflict()
$('body')...
})(jQuery);
It depends on:
Do you want to reuse the functions?
- If yes, your structure is a good way to do it
How long is your code?
- If your code is not too long and not use anywhere else. I think you don't need to break it into functions.
I always put the functions before the document ready:
$(document).ready(function() { ... });
Which I would write in short-hand:
$(function() { ... });
Ideally it is better to have just one initialiser like above. This may be useful for you too if you want to write extensions/plugins in jQuery context.
Related
My colleague has been extensively using IIFE inside (document).ready in his code. Now, I've read this post:
JQuery best practise, using $(document).ready inside an IIFE?
This got me thinking if we should use $(document).ready inside IIFE or is it also fine the other way around as my colleague is doing.
So basically, his code is setup like this:
jQuery(function() {
(function($) {
//...
// Code here
//...
})(jQuery);
});
Is what he is doing generally fine?
Some may argue that this is a matter of style/opinion, but if you consider the typical goal of an IIFE in that context I believe the answer is yes, it is acceptable to use your alternative way, but there is a potential drawback.
Wikipedia has to say that:
Immediately-invoked function expressions can be used to avoid variable hoisting from within blocks, protect against polluting the global environment and simultaneously allow public access to methods while retaining privacy for variables defined within the function.
Neither method pollutes the global namespace, because they don't declare any variables. Therefore, it should be fine to use either way. Although note that it is partially redundant because the function handler for the ready event already creates a new scope, and also note it is the most common practice to see IIFE functions encapsulate all of the code in a file.
One drawback to the way that your colleague is using: If you did want to do some javascript logic that didn't depend on the DOM being ready, then you would not have the benefits of the IIFE if you put your code outside of the IIFE. So something such as this would not be safe:
// Non-DOM-ready-required code here (NOT scope-safe)
jQuery(function() {
(function($) {
//...
// DOM-ready-required code here
//...
})(jQuery);
});
Using the common style gives you the full IIFE benefit:
(function($) {
// Non-DOM-ready-required code here (scope-safe)
$(function() {
//...
// DOM-ready-required code here
//...
});
})(jQuery);
In my opinion, your colleague is jumping through an extra hoop for no reason. I'm going to ignore the outer $(document).ready as it's of no real consequence.
/*jQuery(*/function() {
(function($) {
//...
// Code here
//...
})(jQuery);
}/*);*/
Using an IIFE as the entire body of the callback to jQuery confers no extra benefit in scope isolation. It's the same as if the code were
/*jQuery(*/function() {
//...
// Code here
//...
});
The only thing that the IIFE has done is allow you to reference jQuery as $.
Now, if there were more substantive code inside the callback, then there could be some benefit in using an inner IIFE. In the following example, the callback contains two IIFEs,
jQuery(function() {
// IIFE
(function($) {
//...
// Code here
//...
})(jQuery);
// IIFE 2
(function($) {
//...
// Code here
//...
})(jQuery);
});
and the use of IIFE's allows scope isolation between the two blocks of code.
Back to the main question:
This got me thinking if we should use $(document).ready inside IIFE or
is it also fine the other way around as my colleague is doing.
Now, to be honest, I don't understand why either of these should be regarded as a best practice, even after looking at your link. The people who answered never explained why it should be a best practice.
Looking at
(function($) {
$(document).ready(function() {
// other code here
});
})(jQuery);
versus
//(function($) {
$(document).ready(function() {
// other code here
});
//})(jQuery);
There really isn't any significant advantage. Just as in my earlier example, the use of the IIFE offers no scope isolation advantage, and does nothing other than to allow you to reference jQuery via $.
However, in the actual linked question , the code looks like this:
(function($) {
// other code here 1
$(document).ready(function() {
// other code here 2
});
})(jQuery);
and in this case, the IIFE does serve a purpose of keeping the variables used in other code here 1 from leaking out to global scope. But this has nothing at all to do with $(document).ready(). Restructuring the code as
(function($) {
// other code here 1
})(jQuery);
jQuery(document).ready(function() {
// other code here 2
});
does the same thing.
The moral of this answer is that using an IIFE to wrap loose code that's not already inside a function gives you benefits, while wrapping code that's already inside a function doesn't give you anything (unless you count changing the reference).
Sorry to ask a naive question but I'm trying to figure out the best way to structure a bunch of code into something that is easier to manage
I wanted to put events and their responses into 'controllers' for different sections of site. I was looking through the book Javascript Web Applications and saw some promising stuff like this (p5 - my comment for what I thing I understand):
var controller={}; // ok- an object literal
(Controller.users = function($){ // creating an anonymous function; I don't get the dollar sign since it seems to work fine without it
var jtClick= function(){
alert('you clicked on me!');
};
$(function(){
$('#view').on('click',jtClick);
});
})(jQuery);
but I also noticed that this did the same thing:
var controller={};
(Controller.users = function(){
var jtClick= function(){
alert('you clicked on me!');
};
$(function(){
$('#view').on('click',jtClick);
});
})();
So do I need to pass jQuery as part of my anonymous function? Is this changing how scope is going to be handled? I updated the title to remove 'fully' since I don't think I'm getting much of this
thx in advance
This is a self-invoking function and allows you to safely use jQuery with other libraries that use $ as a library object/variable.
$ in the above example is nothing but the jQuery object that is being passed while invoking the function.
I'm refactoring about 600 lines of javascript into the module pattern. Here is a start from previous post:
I undertand the concept of anonymous methods...and sefl-executing....but not the scoping concepts...i.e. what global and window do.
window.onload=initialize_page;
(function (global) {
global['test'] = 'test';
function initialize_page()
{
/* fill here */
}
})(window);
Can I put window.onload=initialize_page into my module pattern? Or does it need to be put outside of it? Can someone explain how the access works?
EDIT 1: per Answer
(function () {
addEventListener('load', initialize_page);
function initialize_page()
{
alert ("hi");
}
})();
It is a global. Don't touch it like that, you'll overwrite any other code that tries to assign load handlers.
Use addEventListener (or attachEvent for old IE) instead. There are plenty of libraries that abstract the functionality.
I'm not an expert, but I think window.onload is a function that gets called, so you reset it to be another function (that you created). You're using it as a macro there. Since initialize_page does not exist when you passed it, it will probably get passed to window.onload as null.
I have the following piece of code on my page:
<script src="/Assets/JavaScripts/myJavaScript.js" type="text/javascript"></script>
<script type="text/javascript">
testAlert();
</script>
And in myJavaScript.js I have the following:
(function () {
function testAlert() {
alert('test alert');
}
})();
It's not calling testAlert. Not sure what I am doing wrong here? I'm trying to avoid global variables and methods. I did something similiar in jQuery and it worked, it just required a $ at the start of the external file. Can somebody please explain what I am doing wrong here and how to make sure I follow best practices?
I put your code in my environment and checked, I got error in mozila error console.
So, Please check it there.
you should put only below javascript function in myjavascript.js file.
function testAlert() {
alert('test alert');
}
Your function in the js-file isn't returning anything. To avoid global variables you could create one global namespace (-like) variable:
var myNS = (function () {
function testAlert() {
alert('test alert');
}
return {testAlert:testAlert};
}());
Now you can use myNS.testalert() in your inline javascript.
JS is made in such a way that you really can't totally avoid globals. (Well, you can, sort of. If you never give anything a name. But that tends to cause more problems than it solves.) When you call testAlert from some other script, you're operating under the assumption that testAlert is global. If it weren't, you couldn't just call it from anywhere like that.
You can minimize the chance of collision, though, by adding your stuff to an object that serves as a namespace, like so:
// don't clear it out if it already exists.
// that way all of your scripts can use your namespace, if you want.
// what you're really trying to protect against, are strangers picking names
// like yours.
if (!window.myNamespace) myNamespace = {};
// example function
myNamespace.testAlert = function() { alert("test alert"); };
myNamespace.testAlert();
This way, the only name that has a good chance of conflicting is myNamespace.
I was going to show an example of a namespaced global...but ya know what? A namespaced global is still a global. Global variables are something you want to try and get rid of in most cases.
You need some sort of global variable so that you can access the method you're looking for. The fact that you have <script>testAlert()</script> means you expect testAlert() to be defined in the global namespace.
What I like to do (especially when using YUI, which you have tagged this question with), is to create a global object that acts as a utility class.
var page = {
init: function() {
// Do some initialization...
},
testAlert: function() {
alert("Test Alert");
}
};
After you do that, you can use the single global "page" variable to access everything you need.
// e.g.
page.testAlert();
// or...
Y.on("domready", page.init, page);
Again, for the second example I'm assuming you're using YUI, since you tagged this question with it.
I like to organize my javascript in namespace style like below. What I want to know : is there another (shorter?) way to call myFirstFunction() from mySecondFunction()? I tried this.myFirstFunction() and it's not working so maybe there's some kind of mysterious trick here that I don't know.
var myNameSpace = {
myFirstFunction: function(){
alert("Hello World!");
},
mySecondFunction: function(){
myNameSpace.myFirstFunction();
}
}
Thanks for your help as usual, people of SO! :)
As written in your example code, this.myFirstFunction() would work. Your code is likely simplified to illustrate your problem, so it would probably help to see the actual code to tell why it doesn't work with this.
One possible reason that it fails would be if the code where you call this.myFirstFunction() is inside a closure. If so, this would be a reference to the closing function, not your namespace and would therefore fail. See here for a contrived example based on your code to see what I mean. Again, having a look at the actual code would probably be helpful to diagnose what's going on.
Your suggestion to use 'this' should work. i.e.:
var myNameSpace = {
myFirstFunction: function(){
alert("Hello World!");
},
mySecondFunction: function(){
this.myFirstFunction();
}
}
Result:
myNameSpace.mySecondFunction() // "Hello World!".
If you want it to be shorter maybe you should consider the following pattern:
Javascript Design Pattern Suggestion
basically for your example:
var myNameSpace = (function()
{
function _myFirstFunction(){
alert("Hello World!");
}
function _mySecondFunction(){
_myFirstFunction();
}
return {
MyFirstFunction : _myFirstFunction,
MySecondFunction : _mySecondFunction
};
})();
I find this to be the cleanest pattern, also providing "private/public" variables in javascript that's otherwise pretty much impossible
In some cases the this keyword should work fine. If you explicitly call myNameSpace.mySecondFunction() then this.myFirstFunction() will execute as intended.
If you are using myNameSpace.mySecondFunction as an event handler it likely will not. In the case of an event handler you would need some way to refer to the namespace you want to use. A lot of JavaScript frameworks provide a way to define what the this keyword refers to. For example, in MooTools you can do myNameSpace.mySecondFunction.bind(myNameSpace) which will cause this to refer to myNameSpace inside mySecondFunction. If you are not using a framework you could make your event handler an anonymous function like:
document.getElementById('myId').addEventListener('click', function(e) {
myNameSpace.mySecondFunction.call(myNameSpace);
});
For more information on the call method I would refer to the MDC page for the call function or you could use apply which behaves similarly to call but passing an array of arguments for the second paramter rather than having a varargs like approach for additional parameters.
All of these suggestions are predicated on defining your namespace as #Harnish suggested:
var myNameSpace = {
myFirstFunction: function(){
alert("Hello World!");
},
mySecondFunction: function(){
this.myFirstFunction();
}
}
For more information about JavaScript function binding I'd highly suggest reading Justin's article on Function scope and binding in JavaScript
If you are attaching to event:
possible issue could be if you are attaching Namespace's function to event, like:
$(el).on("click", nameSpace.myFunc);
....
nameSpace = {
myFunc: function(){
this.anotherFunc();
}
}
that will throw error.
Solution 1
You may change this.anotherFunc() with nameSpace.anotherFunc()
Solution 2
You might change
$(el).on("click", nameSpace.myFunc);
// to ----->
$(el).on("click", function(){ nameSpace.myFunc(); } );