I have the following code:
(function($) {
"use strict";
$(function() {
// jQuery code here, eg:
$('body').css('padding-top', $('.nav').height());
// I want to call that func here...
});
}(jQuery));
And custom function:
function xyz(a,b) {
// do something with "a" and "b"
}
Where should I place my custom function? Before (function($) {, before $(function() {, or inside $(function() {});?
The difference is the scope.
Location : Scope
----------------------+--------------------------------------------------------
before (function($) { : in global scope, easy to call & modify from everywhere
before $(function() { : in "source module" scope / jQuery closure
inside $(function() { : in "$(function" scope
So that choice gives you the means to organize the access to your code.
In most cases you want to hide stuff to prevent unintended interactions, but in some cases (e.g. log function), you want to have access from everywhere in your web application.
If you do not need to call xyz() from outside $(function, keep it inside. If you do just need to call it within the module, keep it inside ( .. (jQuery)). If you need to call it from everywhere keep it outside in global scope.
Since you want to call the function inside the ready handler, declare it inside it
jQuery(function ($) {
"use strict";
// jQuery code here, eg:
$('body').css('padding-top', $('.nav').height());
// I want to call that func here...
xyz();
function xyz(a, b) {
// do something with "a" and "b"
}
});
But if you want to access xyz from outside the scope of the dom ready handler you will have to declare it outside the scope of the dom ready handler. Now the method is local to the dom ready handler and thus accessible only inside it.
Also as shown above you can shorten the use of IIFE and dom ready handler as shown above
Related
I'm having some issues with running some functions from an external js file.
The html includes:
<script src="js/file.js"></script>
<script>
$("#center-button").click(function() {
explodePage("center");
});
</script>
The js file includes:
var explodePage = function(button) {
//code here
aboutPage();
}
var aboutPage = function() {
//code here
}
The explodePage function runs fine, but as soon as it reaches the call to the nested aboutPage function, it starts throwing these uncaught typeerrors at me. It works fine if I don't use an external js file and just put everything into the html. Pretty new to this so probably missing something obvious in scope or something. Any solutions?
Declare the function's definition as below:
function explodePage(button) {
//code here
aboutPage();
}
function aboutPage() {
//code here
}
Explanation:
When you use the var keyword for declaring functions, the execution of JS happens as when the variable is initialized, you cannot reference or use variable's before declaration. In contrast with the name function defintion JS interpreter first picks the enclosed functions before execution and initializes it before the code execution. This is called AST- Abstract syntax tree that is followed by JS interpreters.
Also Remember:
Also bind your Jquery code inside a Jquery document ready function, just to make sure the Jquery and the DOM elements are available for the bindings.
It's not a good a idea to pollute the global window object with variables, since there can be collisions. And immediately-invoked function expression is a good solution for this.
(function(){
//You can declare your functions in here, and invoke them below
$( document ).ready(function() {
//Check that the DOM is ready, in order to manipulate it an add events
$("#center-button").click(function() {
explodePage("center");
});
});
})($); //Notice that we are injecting a dependency, in this case jQuery
I was told to avoid public variables and conflicts, it is better to place the whole plugin in an anonymous function. I tried to do this but functions do not work anymore.
Here is a simple example:
(function($) {
function changeIt() {
$("button").text("off");
}
}(jQuery));
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button onclick="changeIt()">On</button>
the function runs by a HTML element but since it is inside another function, the element cannot find it.
1- How can I make it working?
2- Is it a good approach to make sure public variables are covered and assumed as private ones?
Thanks
inline events defined on elements only have access to the global scope, so, when you moved that function out of the global scope and into the scope created by the anonymous function, it was no longer accessible to the inline event.
You have two options:
Stop using inline events
(function($) {
function changeIt() {
$("button").text("off");
}
$("button").click(changeIt);
}(jQuery));
Or define it globally
//(function($) {
function changeIt() {
$("button").text("off");
}
//}(jQuery));
This has to do with scope. The changeIt function only exists within the function($). If you want to add it to public scope its best to create an object the prototype the functions.
(function($) {}(jQuery)); -> This will create a private scope, basically your function won't be defined inside window, but inside this private scope.
<button onclick="changeIt()">On</button> -> This will try to execute changeIt from window, which will be undefined.
It's because the function is no more in the global object and thus the onclick event handler in the html element cannot find it by name.
Change your html to
<button id="mybutton">On</button>
and your code to
(function($) {
$("#mybutton").click(function(){
$("#mybutton").text("off");
});
}(jQuery));
and it will work because the handler will not need to be looked up by name
Since changeIt is not found in the global scope (window in the case of a browser), the function isn't triggered on a click. In fact, your console should show an exception like: "Uncaught ReferenceError: changeIt is not defined".
To remedy this, and keep your function structure, set the handler from within the "onload" handler:
(function($) {
$('#myBtn').on('click', function () {
$("button").text("off");
});
}(jQuery));
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="myBtn">On</button>
The Google Analytics tracking code looks like this:
(function() {
code
})();
What's the technique they are using with those brackets - (stuff)() - called? What does it do?
I put the Google Analytics code before the closing head tag on my page and then put an if statement around it like this (I include a Jquery cookie plugin further up):
<script type="application/javascript">
if ($.cookie('allowcookies') == 'yes') {
analytics code
}
</script>
It didn't run until I used the same technique around my code:
(function() {if ($.cookie('allowcookies') == 'yes') {
analytics code
}
})();
Why did it not run before I did that? Why did it run after?
(function() {
/* code */
}());
It's commonly known as «self executed anonymous function (¹)» (o «immediate function invocation») and its main use is to avoid the creation of variables into the global (or in the outer) scope.
It's also used as shortcut when you want to create a function to execute just once, without the need to first define the function with its own identifier and then soon make the function call.
It may be eventually used inside a scope and then it may create a closure if the outer context (or other references) are binded through parameters passing, e.g.
/* outer scope */
(function(outerscope) {
element.onsomeevent = function() {
/* do something with outerscope */
};
}(this));
Another practical use I make with this expression is when I need to create a function to be soon executed inside a constructor function when it is called with new keyword (instead of an explicit call to some init method).
(¹) — as stated on book "Mantainable Javascript" by Nicholas Zakas (O'Reilly, ISBN 978-1-449-32768-2) page 44, the suggested expression is (function() {}()), with nested parens (even if (function() {})() will work anyway)
[...]To make it obvious that immediate function invocation is taking place, put paretheses around the function[...]
See also Immediate function invocation syntax
The "function(){code}" part only creates a function, the () at the end call the created function.
You could rewrite
(function() {
code
})();
As
var x = function() {code};
x();
It's just a select calling function. The () at the end causes it to be called automatically.
It's used like this to isolate local variables that are relevant only to your code from the global scope.
For example:
(function() {
var x = 5;
window.y = 6;
})();
x is available only in the scope of the function, y is globally available through the window.
As to it not running, I'd hazard that's down to the conditional you supplied.
I have some functions in a JQuery document ready method that I would like to reference from other external files, but I keep getting a function undefined. How can I make those global?
ex.
external file 1
$(function ()
{
function DoSomething()
{
Do something
}
});
external file 2
$(function ()
{
Call DoSomething()
)};
declare the functions outside the jQuery escope.
external file 1
function DoSomething()
{
Do something
}
external file 2
$(function ()
{
Call DoSomething()
)};
You can either define the function outside .ready() (as the other answers suggest), or you can take advantage of the fact that the window object is the global scope. So, you can make them global like this:
$(function(){
function doSomething(){
// …;
}
window.doSomething = doSomething;
});
Note that in this case they’ll only be defined after .ready() runs — if you want to use them immediately in another file (i.e. not inside an event handler or another .ready() function), this won’t work.
You probably want to define functions outside ready blocks. That does not hurt. Only executing a function outside a ready block can cause issues if it uses the DOM before it's ready.
Defining does nothing (yet), and as such does not use the DOM. So it does not need to be inside a ready block; doing so only constrains the places where you can access it, which is basically only a disadvantage.
external file 1
function DoSomething()
{
Do something
}
Whenever possible, declare functions outside of the ready check.
external file 1
function DoSomething()
{
Do something
}
external file 2
$(function ()
{
Call DoSomething()
)};
Below is the code I am using in a project with some complex dependencies. After I have made sure that all the dependencies have been loaded I fire the onReadyCallback() also given below. I have two questions :
Is it correct to use, anonymousHandler.apply(MyNameSpace), the apply method on an anonymous Handler being called for Document.ready
From what I understand, because I am using the apply method the anonymous function will fire immediately irregardless of document's ready state. Then how can I pass in the context of MyNameSpace to the anonymousHandler so that "this" inside the function refers to MyNameSpace
var onReadyCallback = function(){
jQuery(document).ready(function(){
if(!this.loggedIn()){
return;
}
...Lots of Code referring to MyNameSpace using "this"
}.apply(MyNameSpace));
};
//load the additional files that are needed and fire onReadyCallback
MyNameSpace.Util.loadFiles(defaultJsFiles,function(){
MyNameSpace.Util.require(['My.App','My.Theme','My.DomHandler'], function(){
onReadyCallback.apply(window);
});
});
How about this, using an anonymous function and call?
jQuery(document).ready(function() {
(function() {
// this == MyNamespace
}).call(MyNamespace);
});
Normally, the ready event jQuery function is called like this
$(function() { /* ... */ });
// or
jQuery(function() { /* ... */ });
// or
jQuery(document).ready(function() { /* ... */ });
Bottom line, the function is not given a particular context; the actual context given by jQuery to the function is the HTMLDocument element, regardless of the argument (in the last example, document). Why is this so is another subject.
Generally, each of these functions are called later, after everything has been loaded, but not necessarily. In your case, there is a reference to MyNameSpace before the ready event happens. Even if Javascript is a LALR-type language, and it will find the symbol declared later, this is not a good practice. What if MyNameSpace would be set to something else later on, before jQuery triggers the ready callback functions? Your ready callback would not get that new reference. Unless intentional, the reference should be made inside the ready callback, when everything is.... ready.
Then, inside the ready callback, there are other techniques to assign a context to a function. lonesomeday have pretty much given the correct way to accomplish what you are trying to do.
(function() {
// this == MyNamespace
}).call(MyNamespace);
The above code executes an anonymous function right away, where this == MyNameSpace
note : the difference between apply and call is decribed here
Now, comes the bottom part of the code you provided :
//load the additional files that are needed and fire onReadyCallback
MyNameSpace.Util.loadFiles(defaultJsFiles,function(){
MyNameSpace.Util.require(['My.App','My.Theme','My.DomHandler'], function(){
onReadyCallback.apply(window);
});
});
This is problematic, and unnecessary. Is the function onReadyCallback only needed there, or will it be called several times? If it needs to be called only once, spare the global namespace, and simply do :
//load the additional files that are needed and fire onReadyCallback
MyNameSpace.Util.loadFiles(defaultJsFiles,function(){
MyNameSpace.Util.require(['My.App','My.Theme','My.DomHandler'], function(){
// if everything is done loading, the function will be executed, otherwise
// it's execution will be postponed later
jQuery(function() {
// create our nicely wrapped anonymous function now
(function() {
if(!this.loggedIn()){
return;
}
// ...Lots of Code referring to MyNameSpace using "this"
})(MyNameSpace); // grab our most recent reference of `MyNameSpace`
});
});
});
If you don't like the indentation (it's merely a developer's taste), replace everything in the ready callback with (something like) :
initMyNameSpace.apply(MyNameSpace);
and create your function outside, on the global space :
function initMyNameSpace() {
if(!this.loggedIn()){
return;
}
// ...Lots of Code referring to MyNameSpace using "this"
};
But I would recommand, at least, to put it in the require callback function so it...
...does not pollute the global namespace with a run-once function
...is not accessible from anywhere (keep it private)
...can be found quickly when editing the source code
etc.
note : usually, apply and call are used to avoid repeatedly accessing objects like some.thing.pretty.deep = value; or when one function needs to be applied to many but not all objects, and thus extending the object's prototype is just not a good idea.
This is my opinion anyway, and how I would do things, without any more knowledge of your code or what you are doing.