Difference between defining a function within document.ready or not - javascript

What is the difference between defining a function within document.ready or not ?
Does it affect the scope of when a function can be invoked ?
Example, is there any issues/differences I should be aware of in location definitions of functions inside() & outside() :
<script>
document.ready(){
function inside(){
alert('inside');
}
}
function outside(){
alert('outside');
}
</script>

Yes, you can only access the inside function from inside the callback for the ready event:
document.ready(function(){
function inside(){
alert('inside');
}
inside(); // works
outside(); // works
});
function outside(){
alert('outside');
}
inside(); // doesn't work
outside(); // works

Does it affect the scope of when a function can be invoked ?
Yes, and nothing else.
(Although your particular example depends on you adding a ready() method to the documentobject first.)

Javascript has function level scoping, meaning if you define a function in document.ready it won't be available outside document.ready
I would define a namespace outside like so:
var app = {};
Then define your inside function like so:
app.inside = function() {
Then inside will be available in your app global namespace.

Related

Not able to define function

I am writing something like
(function($){
function showAlert(){
alert('test');
}
})(jQuery);
and when I tried to run showAlert(), it's saying showAlert() is not defined.
Can anyone suggest why ?
The scope of a variable in javascript is either
the global scope
the function in which it is defined
showAlert is a variable. It's only available in the scope of the external function you wrote.
If you want to define a function for the external scope, define it in the external scope.
I suppose you're calling that function outside IEFE function.
Calling it outside won't work as it is not in global scope. The IEFE is creating a closure of which , showAlert becomes a part and not of global scope which is window
Do this:
(function($){
window.showAlert = function(){
alert('test');
}
})(jQuery);
It doesn't make sense to put a function declaration inside IEFE unless otherwise it is a jquery plugin. So, just remove it:
function showAlert(){
alert('test');
}
You're Creating A function inside a self executing anonymus function ie. $(document).ready() or $(function()....
So your function is in local scope of that function. Simply Means You cant access that in outside of that function.
So to make it accessible just make it global.
In JavaScript window is global object. So to make your function global, use that object as follows:
$(document).ready(function() {
function showAlert()() {
alert('test');
}
window.showAlert=showAlert(); //NOTE THIS, IT IS IMPORTANT.
});
Now you can access it elsewhere in your JS.
Here is working Fiddle
Hope it'll help you! cheers :)..
If you want to extend jQuery with your function just add function to jQuery object.
Like this:
(function ($) {
$.extend({
showAlert: function () {
alert('test');
}
});
}(jQuery));
Separate this code into file with name jquery.showAlert.js, include it after jquery library
and after this you can use function in this way:
$.showAlert()
Best regards.
This should work!
function showAlert(x) {
alert(x);
}
showAlert($('#anyElementId').val());
Assign the variable X for function and your alert. Then pass your element val into your function call.
Demo: http://jsfiddle.net/94ZtT/

Why is a named function inside an "Immediately Invoked Function Expression" undefined when invoked from HTML?

I had this code:
Javascript
(function() {
function read() {...}
})();
HTML
<body onload="read()">
Console said, read is undefined.
After deleting the IIFE it worked, why?
Thanks. :)
Here's a long but satisfying explanation about JavaScript scope and closures.
Since you declare read inside a function, it is local to that function.
Anything you declare inside a function will be local to it.
You can explicitly put it into global scope by assigning it as a property to window:
(function() {
function read() {...}
window.read = read;
})();
Writing
(function() {
function read() { ... }
})();
Is very nearly the same thing as writing
(function() {
var read = function() { ... } //this is different, but not significantly so
//for purposes of teaching this point
})();
and I think you should already understand why a var declared inside a function is not available outside of that function's scope.
The behavior of a function definition (function read() { ... }) is slightly different from the behavior of assigning a function expression to a variable (var read = function() { ... };) in terms of when the name of the function and the function become associated, but the two are otherwise identical.
Because it isn't defined globally. It's only been defined within the scope of that immediately invoked function. To make it global either use this:
function read() {...}
(function() {
...
})();
Or this:
(function() {
window.read = function() {...}
})();
Or better yet, just bind the onload event within the immediately invoked function:
(function() {
function read() {...}
window.onload = read;
})();
In this case the definition of read is inside the IIFE. This limits the scope of the function to the IIFE and any child functions inside of it. The handler for onload is executed in the global scope and hence doesn't have access to read

trying to pass `this` through a function

I have a function localised to the main function and i want to use this to call it but it doesn't seem to work.
My code has:
function option(room,slot){
var div_id = document.getElementById(room);
var opacity = window.getComputedStyle(div_id).opacity
transition_opacity(div_id,opacity,0,function(){this.load});
function load(){
console.log('test'); //does not happen
}
}
Have i misunderstood the use of this or is the scope lost when i use function(){} to call load?
From your code it is not obvious, what object this could refer to. It depends on how option is called. However, if you define the load function inside of the option function anyway, it is best to just reference it directly. You will have to move the declaration of test above the transition_opacity call though:
function option(room,slot){
var div_id = document.getElementById(room);
var opacity = window.getComputedStyle(div_id).opacity;
function load() {
console.log('test');
}
transition_opacity(div_id,opacity,0,load);
}
As you can see, I just reference load directly. You could make another function which calls the load function inside (i.e. function() { load(); } – note the parentheses which calls the function) but that would give you no benefit but would just add another unneeded function to the stack. So just refer to the actual function itself.
For more information on the this keyword, check out this question. Spoiler: It’s more complicated than you would expect.
The scope of this is lost in this instance, probably pointing to the document. You can capture this to a variable in the outer scope to make this work as intended.
var context = this;
transition_opacity(div_id,opacity,0,function(){context.load();})
The above will not work however. This is because load does not exist on the context of this. You would need to define the load function as such:
context.load = function(){
console.log('test');
}
Both.
First, your load function is not a member/property of any this, the way you have it coded. Your load function is simply a nested function that exists within your option function, as has been sort of implicitly noted in other responses.
In your option function, if you want 'load' to become a member of 'this', you'd need to say so, like this:
function option(){
this.load = function(){}; // now load is actually a property of whatever this is
}
Second, you and the other poster are correct that 'this' is no longer the same 'this' by the time your anonymous function is called.
Whenever you call a function, a brand new 'this' is created and exists within the scope of that function. If you just call a function like this:
transition_opacity(args);
.. then within transition_opacity, 'this' just refers to the window object, or maybe window.document. For 'this' to refer to anything other than window or window.document, you need to (in effect) do one of the following:
myObject.transition_opacity(args);
transition_opacity.call(myObject, arg1, arg2, ..);
transition_opacity.apply(myObject, argArray);
or
var myObject = new transition_opacity(args);
In each of those cases, within transition_opacity, 'this' refers to myObject (or, well, in the last case, it refers to a new object that is being created and assigned to myObject).
Here is a way to do what it looks like you're trying to do:
var MyNamespace = {
option: function(room,slot){
var div_id = document.getElementById(room);
var opacity = window.getComputedStyle(div_id).opacity;
var _this = this;
transition_opacity(div_id,opacity,0,function(){
// Careful! Inside here, 'this' is just window or window.document,
// unless transition_opacity sets it to something using call or apply,
// in which case that 'this' is probably not the 'this' you want.
// So carefully refer to the saved instance of 'this':
_this.load();
});
},
load: function(){
console.log('test'); // now it should happen
}
}
.
.
MyNamespace.option(room, slot); // inside option, 'this' is MyNamespace.
Here's another way to do it:
function MyClass(){};
MyClass.prototype = {
// all the same stuff that is in MyNamespace above..
};
.
.
var myObject = new MyClass();
myObject.option(room, slot);
Clear as mud?
Just use
transition_opacity(div_id,opacity,0,load);
You have defined a 'load' within another function as an 'Function Declaration', so now it is only accessible within 'option' function and in other functions defined in this one by name 'load'. You can't access it by using 'this.load' no matter what 'this' is. If you want to access 'load' function as 'this.load' you can try this example to understand how 'this' keywoard works
// Function Declaration
function f1(callback){
callback();
};
// Function Declaration
function f2(){
// Function Expression
this.load = function(){
console.log("test");
};
f1(this.load);
};
var obj = new f2(); // test, this == obj, so obj.load() now exists
obj.load(); //test, this == obj
f2(); //test, this == window, so window.load() now exists
load(); //test, window is the global scope

can't access variables in another javascript file

So i have link every file needed into the index.html file :
<script src="jquery.js"></script>
<script src="notify.js"></script>
<script src="script.js"></script>
i create an object in 'notify.js' :
var notify = {
newNotification : function(text) {
}
}
script.js :
alert(notify.newNotification);
When i try to access the 'notify' object in 'script.js', it works just fine.But i want to use jquery so i add $(document).ready() to both of the file like this:
notify.js
$(document).ready (
function() {
var notify = {
newNotification : function(text) {
}
}
}
)
Script.js:
$(document).ready (
function() {
alert(notify.newNotification);
}
)
And after i add that, it comes up with notify is not defined.What's wrong? Can anyone explain why it doesn't work?
As you have defined var notify in notify.js inside $(document).ready( which is an anonymous function and var notify scope is limited to this function only .
So it is not accessible outside the $(document).ready( function
To make accessible outside don't wrap it in $(document).ready( function
like this:-
var notify;
$(document).ready(function () {
notify = {
newNotification: function (text) { }
}
});
Like everyone else here already pointed out: Only use $().ready when you're handling DOM-Elements and your Variable is not accessible because you used the var keyword (like you're supposed to). The var keyword limits the defined variables to the current scope, which is the scope of the anonymous function you use as your DOM-Ready-Handler.
So, removing the unnecessary $().read will temporary solve your problem.
BUT(!) you should wrap your code into a closures to avoid messing up the global scope and to avoid possible naming conflicts with 3rd-party code.
Like that:
notify.js
;(function ($, window, undefined) {
var notify = {
newNotification : function(text) {
return text;
}
};
})(jQuery, this);
script.js
;(function ($, window, undefined) {
alert(notify.newNotification());
})(jQuery, this);
So, now you'll have the same problem as before, you don't have access to your Object.
Sure you could just add your notify Object to the global scope as Arun P Johny suggested in his answer, but i'm pretty sure over the time there will be more Object you'll need to make global accessible.
If you put each of them in the global scope, you start messing up the global scope again, so my recommendation would be ONE global Object that will hold all other objects/variables you need globally accessible. (Or even better use something like requirejs
Somethink like this:
main.js
;var MyApp = {}; # Only variable in global scope
# Maybe some more initalization code here, dunno
notify.js
;(function ($, window, undefined) {
MyApp.notify = {
newNotification : function(text) {
return text;
}
};
})(jQuery, this);
script.js
;(function ($, window, undefined) {
alert(MyApp.notify.newNotification());
})(jQuery, this);
Some interesting Q/A's about scope and closures here on stackoverflow:
What is the scope of variables in JavaScript?
How do JavaScript closures work?
JavaScript closures vs. anonymous functions
A good Answer about messing around with the global scope:
What is meant by “leaking” into global scope?
In this case there is no need to wrap the notification object in dom ready... because from the looks of it you are not creating any dom element reference while creating the object... the only thing that matters is any method invokation that deals with dom element has to be done on dom ready.
var notify = {
newNotification: function (text) {}
}
$(document).ready(function () {
notify.newNotification()
})
if you declare the variable inside a dom ready handler then it becomes a local variable to the dom ready handler... so it will not be accessible outside the dom ready handler...
Another solution is to add the variable to the global scope within the dom ready handle like
var notify;
$(document).ready(function () {
notify = {
newNotification: function (text) {}
}
})
or
$(document).ready(function () {
window.notify = {
newNotification: function (text) {}
}
})
You only need one document.ready
And this only declare the variables that will move freely in their scripts.
See the example:
script.js:
$(document).ready(function(){
// declare the variables as global
$.varA, $.varB, $.varC;
});
notify.js:
function doNotify(){
// your code here
$.varA = /*your code here */
}
function otherFunc(txt){
// your code here
$.varB = txt;
}
All of your JavaScripts will load before the document is ready.
Create a separate function in script.js that references the notify object, then call that function from $(document).ready
Try this.
var notify = {
newNotification : function(text) {
}

What is this code in Javascript?

On some JS code on some sites I see Javascript code such as this:
SomeName.init = (function () {
// some stuff
})();
I mean, this is not a jQuery plugin code such as this:
(function( $ ){
$.fn.myPlugin = function() {
// Do your awesome plugin stuff here
};
})( jQuery );
Then, what is it? and what is the resulting JS object?
It's a anonymous function, which doesn't leak variables to the global scope when declaring variables using var.
SomeName.init = (function () {
return 3.1415;
})();
SomeName.init is a number (3.1415), because () after the anonymous function declaration executes the function. There's no way to obtain the original function, unless defined within the anonymous function:
(function foo(){
//foo refers to this function
too = foo;
})();;
//foo is undefined
//too refers to the function, because `too` has been defined without var
The Module Pattern. And those two snippets have more in common than you think.
(function () {
// some stuff
})()
is a anonymous function that calls itself instantly. It's just a closure around the code inside to stop the variable scope becoming global.
Whatever the function returns.
(function() {
//...
})();
Is used as a way to namespace code, or declare self-executing constructors. The resulting object is whatever that self-executing function returns.
The second snippet doesn't return anything and there is no resulting JS object.

Categories

Resources