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!
Related
Check out this piece of JavaScript code:
(function (w, d) {
var loader = function () {
var s = d.createElement("script"), tag = d.getElementsByTagName("script")[0];
s.src = "https://example.org/script.js";
tag.parentNode.insertBefore(s,tag);
};
w.addEventListener ? w.addEventListener("load", loader, false) :
w.attachEvent("onload", loader);
}) (window, document);
Why did the author of this code use this method to include a script in the document?
And what is the usefulness of the line:
w.addEventListener ? w.addEventListener("load", loader, false) :
w.attachEvent("onload", loader);
Last point: I'm a JavaScript beginner, what is the (window, document) at the end?
The first question, the code checks to see if window.addEventListener is defined. If it is, it uses it, otherwise it uses window.attachEvent. This is for browser compatibility.
The 2nd question, this code is an anonymous function which takes 2 parameters, w and d. This function is immediately called, passing the parameters window and document.
The following addEventListener line is to register the function so that it gets called when the page finishes loading. Internet Explorer and Firefox (et al) use different functions to do this.
w.addEventListener ? w.addEventListener("load", loader, false) :
w.attachEvent("onload", loader);
In javascript a function is an object in and of itself. As such it's 'value' can be assigned to a variable or consumed immediately. To consume it immediately it must be wrapped in parentheses (otherwise it won't do what you want) and then call it like it were a regular function.
(function (w, d) { ... }) (window, document);
It's more obvious what is going on if we break it up across two lines.
var a = function(w, d){ ... };
a(window, document);
It was done this way to as to not pollute the global scope with temporary values or functions. Not to mention not trashing anyone else variables. This can be broken into two parts:
By encapsulating the code in a closure anything explicitly declared inside is in the closure's scope, not the global scope. var loader is in the closure's scope.
By consuming the closure immediately it won't be stored in a variable in the global scope. Since it was declared anonymously it won't exist as a named function in the global scope.
Firstly, w.addEventListener ?to make sure if the browser supported the addEventListener method of window
Secondly, (window, document) is just parameter call of anonymous function he wrote before function(w,d) {}
It looks like the author is waiting for the page to be fully loaded before attaching the script tag. addEventListener (DOM level 2) and attachEvent (Microsoft stuff) are more flexible ways of attaching events. The code is similar to saying w.onload = loader.
The last bit is passing arguments into the anonymous function, where they are named w and d. By putting the () at the end, the anonymous function is invoked right away.
So the function is wrapped in a closure. Which in turn means w = window and d = document.
When the method is called the it creates a function called loader which is the callback for one of the two possible event listener triggers (meaning, that'll be called when the load or onload event is called on the window).
The x ? y : z syntax is a shorthand if then else call.
If we expanded that out, it'd look like this:
if (w.addEventListener) {
w.addEventListener("load", loader, false);
} else {
w.attachEvent("onload", loader);
}
that statement is used cater the method for both IE and other browsers.
The author of this code is using an anonymous function wrapped in a closure to fire off the function, which registers a load event. The script on the page will not actually be loaded until the window's onload event fires.
The reason that the author may be delaying the script load may be to give the web page more time to render before actually loading in the other script. This is a great technique to load page content quickly while delaying the loading of resources that are not immediately needed.
The technique the author is using is an anonymous function wrapped in a closure. Picture this:
myFunction (window, document);
Now, I'm going to replace the function call with an anonymous function:
function(w, d) {
// do stuff
alert("w = " + w);
alert("d = " + d);
}
Now I'm going to cause that function to run immediately, without actually giving it a name. I'm also going to pass two parameters into that anonymous function:
( function(w, d) {
// do stuff
alert("w = " + w);
alert("d = " + d);
}) ("1234", "5678");
The output in this example would be:
w = 1234
d = 5678
If you watch the parentheses and match them up, the first outer parentheses matches the closing parentheses on the last line at character 2, that is the function name, and the following set of parentheses wrap the two values passed into the function as parameters.
This can be a tough concept to grasp at first; after you see it done a few times, it starts to make more sense.
Adding the script that way allows the author to include that script in the document without directly editing HTML files. Can also be used to dynamically load a script only when needed. (i.e. if you have a bunch of code to edit something on the page, you don't want to download it until the user actually clicks the edit button, so you don't waste bandwidth when it's not needed).
addEventListener and attachEvent are ways to trigger a function to be called when the page has finished loading. In this case, there's a function named loader
The reason for both is that some browsers support one and some support the other. I've been using jQuery long enough that I don't remember which is which.
(window, document) is a way to encapsulate those variables in scope and/or refer to them by shorthand w and d. The author is creating a function that expects those parameters, then passing both window and document as the arguments for them.
The closure also helps the author keep from having his script clash with other scripts on the page. Think of every variable declared in there like it's a private variable in other languages.
This is effectively the same as:
function RegisterEventListener(w, d) {
var loader = function () {
var s = d.createElement("script"), tag = d.getElementsByTagName("script")[0];
s.src = "https://example.org/script.js";
tag.parentNode.insertBefore(s,tag);
};
if (w.addEventListener) {
w.addEventListener("load", loader, false);
} else {
w.attachEvent("onload", loader);
}
}
RegisterEventListener(window, document);
The only real differences are:
If you define an anonymous function (using function () {};) without assigning it to anything it is only available for limited use (because there is no way to reference it). At the same time, anonymous functions also allow immediate execution (like the one in the code from your question function(a, b) {}(a, b);.
The condition ? true : false (tertiary operator) is just shorthand for writing simple if statements so it requires less typing to write out, but some people also see it as being less readable.
The window, document at the end of the first block of code are arguments to the anonymous function defined in the rest of the code block. Since Javascript is pretty much a functional language programmers are allowed to define these anonymous functions and even use them without giving them a name.
The block of code you pasted with the question mark is an example of infix notation, a language construct that fits this pattern: condition ? ifTrueExpression : ifFalseExpression. Where condition is true, the entire expression will be equal to ifTrueExpression. Otherwise, the entire expression will be equal to ifFalseExpression.
The use of infix notation you pasted is common in detecting which type of internet browser is being used. Although, I'm not sure which browser this block of code is trying to detect, its intent is to implement an event handler in a browser specific way.
I may be wrong, but this is the implementation used by Google with their analytics script.
This is called a closure, a function that is autoexecuted and enclose the variables inside, so they can't mess with your code.
This codes essentially creates a script tag and append this to the DOM before the first script tag it finds in the document.
The answer for the first question is about browser compatibility. some browsers use addEventListener and others attachEvent to attach events to elements in the page (in this case, the window) and it will lounch on the load event of the window (when all content is loaded, after the document is ready). Take a look at this for a more detailed answer: window.onload vs $(document).ready()
The second answer is simple. This are the parameters used in the closure (the auto calling function) and can be read in this way:
function anonymous(w, d) {
...
}
anonymous(window, document);
when using the module pattern in js i've notice that the main benefits are private members and not cluttering the global namespace, but what i wanted to know is, is this:
(function(){
//some code...
})();
the same as this:
window.onload = function(){
//some code...
}
they both provide private members and both don't clutter the global namespace. the only difference i can see is that if both are manipulating DOM elements the second one can be called anywhere within the document (because of document.onload) while the first has to be called ether at the bottom of the body node or right after the close of the body node.
are there any other differences between the two that i may be missing?
One major difference is that the latter will overwrite any existing window.onload that may have been set earlier on the page — and will, in turn, be overwritten by any later ones. (This can be addressed by using window.addEventListener instead.)
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.
We use a bit of javascript that overwrites the setTimeout method for IE. This is because in some versions of IE the parameters do not get passed correctly (see here).
I have to load the modified setTimeout script first, because if I load it after the code that calls setTimeout is parsed (not run) then the modifed version does not get called.
What happens when the javascript engine parses files that have method calls to methods at the global scope? Do the mappings to the methods get created at parse time or when the code is executed?
EDIT
I have had a few answers to this question, which give other solutions to this problem, but the problem at hand is not my concern as I already have a solution for it. What I want to gain by this question is a better understanding of how javascript is parsed and run.
Methods are created at when the code is executed.
If the semantics of the code is correct interpreter is able to execute code.
While parsing nothing wasn't be executed.
File after parsing is executed singly one by one , before parsing the next.
Check this out:
We have two js files.
<script src ='1.js'></script>
<script src ='2.js'></script>
In second file we put declaration of setTimeout;
//file2
window.setTimeout = function(){};
In first file we'll checking for setTimeout being overridden
//file1
var f = function() { alert( setTimeout ); };
f();// alerts native setTimeout
setTimeout( f, 1000 ); // We use native settimeout, propably after one second file2 being loaded and executed and function `f` will be alerts the overriden setTimeout
If methods which I added were would be created during parsing. This would have access to it anywhere in the script in which it was created, even before its declaration.
so:
//somefile.js
setTimeout(); // we do not have access to function declared below, so while parsing this wasn't created.
window.setTimeout = function() { alert( 'whatever' ); }
EDIT #2
Fiddle #1 - http://jsfiddle.net/zEaL8/4/ - Allows you to set/reset a native function. To see how the redefinition and calling order works.
Fiddle #2 - http://jsfiddle.net/aKnjA/1/ -Demonstrates that the order of definition does not matter. Notice that the redefinition happens after the browser parses the call to the function.
EDIT
To answer your question: Javascript does not enforce any order of definition of functions. i.e. we can call a function defined afterwards in code. When the browser parses a line of code that calls a function that is defined afterwards, it does not have any clue as to where to find that function. This being the case, it is clear that binding happens only at run-time and not during initial parse. This in effect would mean that your redefinition of setTimeout is what will execute. The only thing to ensure is that the redefinition of setTimeout itself gets executed before any call to that is executed.
To ensure that the redefinition of your new setTimeout is processed first, you can place it in a script block as the first element inside the head node outside load, domReady etc.
i.e. Something like:
<html>
<head>
<script>
window.setTimeout = function() {
alert('new sT');
}
</script>
</head>
<body onload="setTimeout();"></body>
</html>
you can store original setTimeout in a global variable at the beginning of the code and then overload the setTimeot with a new function.
window.oldST = setTimeout;
window.setTimeout = function(funct,x) {
return oldST(funct,x);
}
so if these are the first lines of the js code you will have overloaded the setTimeout function with yours and set the old one in oldST.
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.