I am learning javascript and jquery and wondered whether it is good or bad practice to nest all my functions within $(document).ready(function). Is there any difference between this:
function someFunction()
{
return someThing;
}
$(document).ready(function()
{
// some code
...
someFunction();
});
and this:
$(document).ready(function()
{
// some code
...
function someFunction()
{
return someThing;
}
someFunction();
});
Be gentle - I'm pretty new to this!
You forgot at least one :-)
function someFunction()
{
return someThing;
}
$(someFunction);
Generally there is no difference between: $(document).ready(argFunc) and $(argFunc).
The other variations you listed have all different scopes for different things.
For example, in your 2nd block you declare someFunction inside a non-global scope, while your first and my example declare it in the global scope, which has implications for reachability.
Also, technically, with both of your variations you produce one extraneous function call. Because in this case, all you call is one function (which you can also write like my example).
UPDATE1:
To add some additional info and to further the discussion about scopes - JavaScript has very loose requirements for existence of variables. If it doesn't find them in the current scope, it wall just traverse the call chain upwards and look for it - until it finds it or not. That is why you can access the jQuery object ($) from anywhere.
There is however this:
someFunction($) {
// You can use $ here like always
return someThing;
}
$(someFunction);
This means, that the handlers (there can be more than one) for the document ready event of jQuery get passed jQuery itself as an argument.
If you specify this parameter for your function, you'll use that one, if you reference it. Otherwise, you are using the global one. That reduces the length of the upward look-up - chain.
That is completely irrelevant from a performance stand point.
But, by specifying this as a parameter, you make it absolutely clear where the jQuery object is coming from. Even that might be irrelevant.
I just wanted to show, that these callback-type functions in jQuery often take parameters that are useful.
So if you are ever stuck and need access to some object you don't have, it might be worthwhile to check the jQuery docs to see, if there is not a parameter, that does what you want.
To conclude this update, I very much like the first comment to the question, which is a much better answer than mine.
UPDATE2:
On the point of multiple callbacks for document ready (or any event binder in jQuery for that matter):
You can do this:
$(func1); // or $(document).ready(func1);
$(func2); // or $(document).ready(func2);
Both will get called as soon as jQuery fires its document ready event. That might come in handy depending on the perspective. Some would say, it encourages spreading your logic around. Others might say, it allows for cleaner separation of all the things that need to be done on document ready.
yes. The first way puts someFunction in the global scope so that it can be called by anyone. If you intend this function to be "private" and only callable by some code then the 2nd way is preferred. Generally you should prefer the 2nd way unless you need to export the function into global scope.
The differences are subtle, but worth bringing up.
Declared functions outside of DOM ready:
If you don't call the functions until DOM ready, then this is more efficient since it is registering the functions before waiting for the DOM to load (Edit: As is noted in the comments, there will be a slight performance penalty in accessing global variables due to scope resolution). This is very minor and probably not noticeable.
More importantly, you functions become globals, and you can clutter the global scope if you're not namespacing properly:
var myFuncs = {
someFunction : function() { ... },
someOtherFunciton : function() { ... }
};
Declared inside DOM ready:
Functions are no longer globals, but your functions are registered along with your other DOM ready code.
I would say it's fine to go either way in most cases, but definitely declare your functions under one namespace.
First off, functions are typically only declared if they are going to be used more than once. If you put a function inside the $(document).ready(function) then it won't be available outside the scope of the $(document).ready(function). Check out an article on Javascript Scope.
This is because $(document).ready accepts a function as a parameter and in your two examples you are declaring an inline function (that's the function () {} code in there). Check out a discussion of inline functions vs parameterized functions.
So, it boils down to deciding if you are going to use someFunction() more than once. If so, put it outside the $(document).ready function. Otherwise, you don't really need a function since you are just calling it once.
As long as someFunction() does not try to manipulate the dom, there is no difference. $(document).ready is called after all elements in the dom have loaded and can be accessed with javascript. If you try to manipulate an item in that page with javascript before it loads, it wont be there and the code will break.
Related
I am trying to understand whether or not the concept behind using multiple initialization functions is bad practice. By an initialization function I mean either of the following:
$(document).ready(function(){
//... some code here
}
(function(){
//.... some code here
})();
Time and time again I have seen multiple initialization functions being used and I always thought that this is ultimately a bad practice, but am I really wrong?
Based on that, would anyone care to enlighten me as to whether is it a good or bad practice to use multiple initialization functions?
Edit: removed irrelevant example of a bad use of closure and encapsulation.
Your suspicion is correct in that it's generally a good idea to organize code when you can.
Centralizing initialization functions makes it easier for another developer to figure out which statements are being executed at any given time. This facilitates debugging and becomes increasingly important when multiple developers are working on the same code.
Perhaps consider doing something like this:
$(document).ready(function () {
function findLionelRichie() {
console.log('found Lionel Richie');
}
function findWhomeverElseNeedsFinding() {
console.log('found all the others');
}
(function initialize() {
findLionelRichie();
findWhomeverElseNeedsFinding();
})();
});
That being said, they cannot always be avoided (for example, when calling functions from external libraries). Try to keep it as organized as you can on your end, however.
Creating a function within another function changes the scope of the function in the same way it would change the scope of a variable.
The functions defined within another function won't be accessible outside the function unless they have been attached to an object that is accessible outside the function:
Can a function declared and attached to the global scope, but having jQuery-dependent code, always be depended on to work properly if it is only ever called from within a jQuery document-ready block?
e.g.:
<script src = "https://code.jquery.com/jquery-2.1.0.js"></sript>
<script>
function myFunc(){ alert( $('#someElem').text() ); }
$(function(){
myFunct();
})
</script>
In practice, I've seen this done a lot, with such functions being written to separate files entirely. I have never seen it fail, but part of me wonders whether or not this is truly safe.
I think at least partially this depends on whether document-ready waits for the completion of the javascript compilation phase of page-load. But are there other reasons this might fail?
Please disregard issues around polluting the global name-space, readability, and so forth. I am only concerned here with reliable execution.
It really can't fail, the $() function that looks up the element is only executed when the myFunc function is executed, and that function only executes once document.ready fires, so the element will be available at that time.
The global myFunc function will also always be available, as long it's defined before the document.ready code in the DOM.
In many cases it will even be available if defined after the document.ready code as DOMContentLoaded (and other such methods) is async and waits for the DOM to be ready, but there's no guarantee that all scripts will be loaded at that time, just that the elements in the DOM are available, so you should generally make sure that the myFunc function is defined before the $(function(){ ... }); code.
Such constructs are written only if myfunct() will be accessible from outside the scope of document.ready(). If other functions / events may also call it, it is better to move it out.
If it is only intended to be called once or on a particular event, it may be nested in the calling function body only.
One may even like to make the function calls fully contained structures like clorjures, and the likes. In that case too, the function would be nested inside another var declaration.
Other than this, there seems no other big difference.
Please add if I missed on anything!
If have a callback that is activated repeatedly such as the following...
Template.foo.rendered = function() {
$(this.firstNode).droppable({
// other arguments
drop: function() {
// some really long function that doesn't access anything in the closure
}
});
}
Should I optimize it to the following?
dropFunction = function() {
// some really long function that doesn't access anything in the closure
}
Template.foo.rendered = function() {
$(this.firstNode).droppable({
// other arguments
drop: dropFunction
});
}
In this case, the rendered callback is a Meteor construct which runs asynchronously over a DOM node with template foo whenever they are constructed; there can be quite a few of them. Does it help to declare the function somewhere in a global closure, to save the Javascript engine the hassle of keeping track of an extra local closure, or does it not matter?
I don't believe that in modern browsers that there will even be a difference. When creating a closure object, V8 determines what variables your function uses, and if you don't use a variable it won't put it in the closure object(I read this somewhere online a while back, sorry I can't find the link*SEE BELOW*). I assume any browser that compiles JavaScript would do the same.
What will be optimized is the creation of the function. In the second example the drop function is created at the same time as the rendered function, in the first it's re-created every time the rendered is called. If this was in a long for loop that might be worth optimizing.
I personally think the first example is a lot easier to read and maintain. And as I said in a comment on the question you(or the person editing this code in the future) could accidentally overwrite the function variable(in an event handler or something) and you could have a hard to find bug on your hands. I would suggest saying with number 1, or wrapping everything in a self-executing function so dropFunction has a smaller scope and less chance of being overwritten, like so:
(function () {
var dropFunction = function() {
// some really long function that doesn't access anything in the closure
}
Template.foo.rendered = function() {
$(this.firstNode).droppable({
// other arguments
drop: dropFunction
});
}
})();
EDIT: I found the link, it was actually in a blog post about a closure memory leak in Meteor!
http://point.davidglasser.net/2013/06/27/surprising-javascript-memory-leak.html
Here's the portion I mentioned:
JavaScript implementations (or at least current Chrome) are smart enough to notice that str isn’t used in logIt, so it’s not put into logIt’s lexical environment, and it’s OK to GC the big string once run finishes.
I'll start this by saying I don't know anything about meteor :/ but if I'm understanding what happens correctly, basically:
Template.foo.rendered
Gets called repeatedly. When that occurs, you construct and object + define a new function on it "drop" which is eventually invoked. If that is the case, you are better off from a performance perspective defining drop once at parse time. But the benefit probably depends on how often rendered is called.
As for why - I posted something similar here:
Performance of function declaration vs function expressions in javascript in a loop
And I think #soktinpk's answer I think is a great summary.
If you look at the jsperf in the above link it may not initially seem directly applicable, but if my assumed statements above are true it is in fact is - because the question at hand boils down to how expensive is to define a function at runtime vs parse time and are you defining this function at runtime over and over again.
If you look at the performance of the loops where a function is defined at runtime vs the loops where functions are defined at parse time (or defined at parse time and hoisted), the parse time loop run significantly faster.
I believe that the equivalent of what meteor is doing in your example is probably something like this jsperf: http://jsperf.com/how-expensive-is-defining-a-function-at-runtime2
What I have done here is created two loops that simulate your scenario being invoked over and over again. The first invokes a function that creates and object and function and passes it to another function for invocation.
The second creates and object that references a function and passes it to another function for invocation. The difference in performance looks significant (58% in chrome).
Just wondering if there's any benefit to using the style: (function() { <code> })(); in your script files proceeding the library scripts. Basically the place where logic goes for setting up the event listeners and other initialization logic.
So for example:
<script>
(function() {
$('div').on('click', 'a', function() {
alert('click');
});
})();
</script>
v.s.
<script>
$('div').on('click', 'a', function() {
alert('click');
});
</script>
The point of the self executing anonymous function in this case is to avoid defining global functions or variables when a true global is not needed. Since your example has neither, it is not needed in this case.
The self executing anonymous function provides a private closure for you to define anything you want and it is isolated from the outside world. It wont cause conflicts with any outside code and outside code cannot directly access the functions and variables inside the closure.
As to your question about whether it's a standard practice, that's really up to you. I personally think it's a good idea because then you are free to define helper functions or an occasional global without touching the actual global space. If you're using $(document).ready(fn), then you already have a closure around your init code so you're already set in that regard. If not, it's up to you. I personally think it's a good idea and see little downside to making it a standard practice. You do, of course, have to remember that if you need a true global variable or function, then you will have to define it on the window object so it's available outside your closure.
No, the first one is only extra code.
Now there can be a case where the first will keep globals from being created.
You need to use the jQuery(document).ready(function(){...}); model to set up event listeners, otherwise um... well, jQuery won't be ready.
I have a script, that based upon specific scenarios, may need to supersede functions to do some processing before eventually calling the original function. (See "'overriding' Javascript Function")
I can get this working in general - here's a basic example using the jQuery plugin Tinyscrollbar (not my intended application, just something quick and easy to illustrate):
(function ($) {
// Snip..
function initalize() {
oSelf.update();
setEvents();
return oSelf;
}
// Snip..
function setEvents() {
(function () {
var oldInit = wheel;
wheel = function (oEvent) {
console.log('Intercept');
oldInit(oEvent);
}
})();
// Original event code, irrelevant to question
}
function wheel(oEvent) {
// Actual function, related to using the mousewheel
}
})(jQuery);
When I scroll the mousewheel, the console prints 'Intercept', and the scrollbar moves as originally defined. Wonderful!
However, the function name is hardcoded, and doesn't live in the global scope, so window[] is unavailable (which I like). Is there any possible combination of black magic, 'new Function()', and/or other way to loop through a potential list of function names (which may change based on other logic) and encapsulate them in this (or similar-in-spirit) manner?
Thanks in advance!
Unfortunately, there's no way to enumerate or dynamically access members in a scope object (with the convenient exception of the global scope/window object)
So you'd need to rephrase your code a bit. Instead of having free-floating functions in your outer function, have objects with methods on them. That'd make replacing those methods much easier.
There's some additional trickiness if you modify your functions after you started assigning them as event handlers or whatever. If you happen to use some kind of bind() wrapper around those functions, the correctness of your behavior will depend a lot on that bind() function.
Specifically, if you want the replacement method to retroactively become the method called for any event handler or callback it was assigned to, you'll want to use a bind() wrapper that takes a context object and a string meant to be the function name rather than a context object and a function reference. (and make sure that bind() doesn't resolve that string early to shave some ms on each calls.)
If don't don't want the retroactive behavior, you still have to make sure you don't have some bind()-ed version of the original method floating around and still being used for new callbacks after your replacement happened.