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
Related
I'm trying to build a Javascript library that will provide some functionality for a JQuery Plugin I'm putting together.
I got the following skeleton code from searching online although I'm not quite sure how it all works (I do know it's a closure). I've added my functions via declarations.
(function(window, document, $) {
function func_1(){
return 1;
}
function func_2(){
return 2;
}
})(window, document, jQuery);
So I put the above code in a separate JS file and then source it in my HTML page, then I run try to run the function like so (Note: I have JQuery set up as well):
<script type="text/javascript">
$(document).ready(function() {
console.log(func_1());
});
</script>
However, I seem to be getting some errors in Firebug (ReferenceError: func_1 is not defined).
I have two questions:
How do I call my functions?!
I'd like to be able to call the functions in the following format: className.functionName(). How do I restructure the skeleton code to enable me do this and, say, call my function like this: Device.func_1()?
Thanks for your anticipated assistance.
The closure is used to hide internal functions from the rest of the code. You need to explicitly expose the public functions of the library:
var Device = (function(window, document, $) {
function func_1(){
return 1;
}
function func_2(){
return 2;
}
var internalDevice = {
func_1: func_1,
func_2: func_2
};
return internalDevice; // expose functionality to the rest of the code
})(window, document, jQuery);
The (function(window, document, $) {})(window, document, jQuery); part is called an immediately invoked function expression (IIFE). It's used to avoid leaking all the library functions into the global scope. Otherwise, if some other library had a func_1 function it would either be overwritten or overwrite your library's func_1.
The arguments to the function are used to control how the library can affect other parts of the code and relies on it. For example, someone might overwrite the window.$ library so that $ is no longer available everywhere in the code. But since you have a local reference in the closure you can still access it.
Alternatively to using the code above - returning an object - you could also assign your library directly to the global scope:
(function(window, document, $) {
...
window.Device = internalDevice; // expose functionality to the rest of the code
})(window, document, jQuery);
I can only answer question number two, but you can create that by doing this:
var Device = {
function func_1()
{
// your first function
},
function func_2()
{
// your second function
}
};
That way you can just call:
Device.func_1();
Hop that helps :)
When something is inside a closure the scope of it is changed to that closure. func_1 and func_2 can only be seen inside the anonymous function calling them and below.
A simple question.
I have a web project includes multi JavaScripts.
JS:
// (1) Event
$('.input').keyup(function()
{
keyUpFunction();
});
// (2) Function
function keyUpFunction(){ ... }
(1),(2) which should come first in one javascript file? If the browser read the function first, does it store the function in memory and invoke it when scan the event.
In some case, the same function is defined in multi javascript . e.g.
prm.add_endRequest(function() {
fn1();
fn2();
});
$(document).ready(.......)
Should I duplicate the function name and define each component in each js file.
or keep the function declare in one file and invoke sub-function composite the function?
Functions defined in the following manner:
function fooBar(){}
Are 'hoisted' to the top of the current scope. This means they will always be available, in the current scope, even if they are defined at the end of the file.
This does not hold true if you defined you functions like this:
var fooBar = function(){};
These functions are not hoisted, and must be defined before they can be used.
It should be noted that in your specific example, keyUpFunction will only be called once a keyup event has fired. This also means that all javascript on your page will already be evaluated, so the keyUpFunction will be defined (parsed) already regardless.
EDIT: To be more explicit, this first example is okay:
doSomething('hello world');
function doSomething(str){
console.log(str);
}
However, this will cause you problems:
doSomething('hello world');
var doSomething = function(str){
console.log(str);
}
#Matt's answer covers the function hoisting stuff nicely.
To avoid function name clashes within multiple files, wrap your content in an immediately invoked function expression, e.g.:
(function() {
// put your variables functions here
...
// register event handlers
})();
Any variables or functions declared therein will be constrained to that scope.
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.
I am relatively new to javascript so please be patient if what i am asking is completely stupid!
I am trying to make a simple module. Inside the module i want to have a config object that holds settings for the module. I am also using jquery. The jquery selectors work only when in a function directly in the main object/module.
I understand that javascript has functional scope so I am suprised that I cannot use the jquery selectors anywhere inside the module.
EDIT:
I want to be able to directly set all of my configs inside the configs object using jquery selectors. This way i keep all the messy stuff inside one place and can then access configs.whatever throughout the rest of the module. At the moment jquery selectors do not work inside the configs module.
var OB = function() {
var configs = {
'mode' : 'test',
'numOfSelects' : $('.mySelect').find('select').length, // This doesnt work
}
var getMode = function() {
return configs.mode;
}
function init() {
alert(configs.numOfSelects); // This alerts 0 until the following line
alert($('.mySelect').find('select').length); // This correctly alerts 2
};
var handlers = {
successHandler : function() {
alert("Success");
},
errorHandler : function() {
alert("error");
}
}
return {
init : init,
getMode : getMode
}
}( );
$(document).ready(function(){
OB.init();
});
It isn't that jQuery isn't in scope — that's that the code isn't executing when you think it is. The variable config is defined when that anonymous function (var OB = function() {}()) is executed. The DOM isn't ready yet, so that DOM traversal doesn't find anything. When you do the DOM traversal in init(), that isn't executed until it's explicitly called inside the $(document).ready() handler, at which point that DOM is set up. That's the difference you're seeing.
OB() needs to be called after the DOM has completely loaded. Hence the answer by Marcelo, which calls OB() in the ready() method.
EDIT: It's funny that my original answer below was incorrect because I didn't notice two little parentheses at the end of the definition of OB, and it turns out that these are the culprit. You define and then immediately invoke OB, which is before the DOM has been fully loaded. Remove those parentheses and make the change I suggest below.
Calling OB() returns an object with init and getMode, but you haven't called OB(), you've only referred to OB. Try this instead:
$(document).ready(function(){
OB().init();
});
Also, I assume you want to later refer to getMode. In particular, you will to get the copy of getMode that has access to the same local scope that your init() call had access to. To achieve this, you will need to store the result of calling OB() for later use:
var ob;
$(document).ready(function(){
ob = OB();
ob.init();
});
function some_other_function() {
... ob.getMode() ...;
}