Use a global variable or not

I have this calendar…just click the book link to make it appear.
In it you will see an event listed on the 20th january of this year named event1.

When you click it the eventClick function is called at line 20 on the JS pane.
Inside that function you will see an object…appointment…

I want this object make it available to the handler at line 61…
How I could possible do that?

You definitely need a global variable to do that.

If you’re wanting the booking to update itself when the checkbox is changed, you should be able to trigger the calendar to update itself, where the booking retrieves the checkbox info and makes use of it for you.

It’s fine to save the appointment variable higher if you want to reference it elsewhere.
One trick you might not be aware of is an IFFE to limit a variables scope.

(function() {
  var appointment;
  
  $('a.app_btn').click(function(e) {
    appointment = {};
  });

  $('.serv_check').change(function() {
    console.log(appointment);
  });
})();

By using that approach the only global variable you need in JavaScript is the one to reference a library (eg the jquery variable when using jQuery). All other variables can be local to the script that uses them so as to avoid script clashes.

I do not quite understand this technique.
First of all what IFFE stands for(assuming it is an acronym)?

How exactly do I limit a variables(namely appointment) scope in this example.

Declaring appointment outside a handler…makes it global.So…how the scope is limited this way?

IIFE stands for - Immediately Invoked Function Expression

JavaScript uses function scope so anything you declare inside a function has its scope limited to that function.

Functions can be nested inside other functions so to avoid having anything at all in global scope - where it can clash with the browser or other scripts - you wrap all of your code inside a function. As the only purpose for this is to remove everything from global scope into its own scope we don’t need to give the function a name as long as we run it straight away when we define it.

To create an IIFE you somply wrap all of your code inside of:

(function() {
// define all your variables here
// your code
}());

With modern JavaScript you can even make sure that all the variables used in the script are actually properly declared inside the IIFE and that you are not accidentally adding anything to global scope.

(function() {
"use strict";
// define all your variables here
// your code
}());

The only variables you ever need to have in global scope are library references. For example if you are using jQuery then only the jQuery variable itself needs to be in global scope. This IIFE variant allows you to use $ as a reference to the jQuery library inside of the wrapper while leaving the global $ to use for other libraries in other code.

jQuery.noConflict();
(function($) {
   "use strict";
// define all your variables here
// your code here
}(jQuery));

I have seen global variables used to reduce the need to pass the variables to functions.

I guess it could be relatively “safe” as long as the names are unique and the script is small enough to keep a handle on what’s going on.

eg. instead of var start = 1; I could use var mitt_start = 1; under the assumption that no other variables but mine would have that prefix.

IMHO though that could work, there is still the risk of values becoming corrupt and introducing unexpected and often hard to solve bugs. (been there, done that)

And I would still need to make sure that variable names were unique according to the context I used them in.
eg. if I used mitt_start as the variable name for both an incrementer and a positioner I would need to rename them mitt_increment_start and mitt_position_start
It can get messy fast. (been there, done that)

Much safer to just keep things in scope and not need to worry about it.

In my example appointment is accessible to both functions inside but not a global. Outside of the IIFE appointment doesn’t exist.

(function() {
  var appointment = {};
})();
console.log(appointment);

If you wrap the entire code in an IIFE then you still don’t need to pass the variables into the nested functions. The only difference is that the scope of the variables is the IIFE instead of global.

With the separate scripts all wrapped in their own IIFE each will still work the same as before except that there are no longer any variables in global scope to potentially clash between the different scripts.

1 Like

Ι have one question…is the document.ready function(in which all JS code goes) considered an IFFE?

I guess it depends where it is.

An IIFE will run as soon as the script is loaded, whether or not the document is ready.

So if it’s before the closing body tag, essentially yes, as the document is ready at that point.

But if it needs to work with a DOM element that hasn’t loaded yet and the IIFE is in the head for example, you’ll get error(s)

Not really as it tests for a condition before running.

If you put all of your scripts immediately before the </body> tag (which is where all JavaScript you want to have interact with the web page should be put) then that condition will be met almost immediately and so the document.ready code will run almost straight away. With the code in the page at that point you can replace the document.ready with a proper IIFE as everything the code is waiting for is actually ready even though the </script></body></html> hasn’t been processed yet in order to trigger document.ready (as there is no way to interact with closing tags from JavaScript anyway).

1 Like

To help aid with clarification, the document.ready code has two different variations.

The following is the original jQuery document ready technique:

$(document).ready(function ($) {
    ...
});

jQuery have updated the above so that you don’t need to explicitly state ready, even though it still waits until the document ready event:

$(function ($) {
    ...
});

We have also done a piece giving further details on the document ready techniques too.

Neither of the above are IIFE, for they are just passing a function to another function.

An immediately-invoked function expression is a function contained inside of parenthesis, that then uses () to invoke that function.

There are two types of IIFE techniques. One is where the () is applied directly to the function, and the other is where the () to invoke the function is applied to the parenthesis itself. I prefer the former technique as you are then directly invoking the function, and not the parenthesis themself.

// an IIFE technique
(function () {
    ...
}());

// another IIFE technique
(function () {
    ...
})();

And as Douglas Crockford says, the latter also looks like dog balls :smile:

A jQuery IIFE could use:

jQuery.noConflict();
(function($) {
    . . .
}(jQuery));

which frees up the global $ variable to be used elsewhere while allowing $ to be used to refer to jQuery inside the IIFE.

Ι did not ask this question about document.ready for no reason…

Is it OK(from a scope perspective) to use an IIFE inside the document.ready function?

Someone might say what could be possibly wrong with it…

I do not know…I am just asking.

Did you have any problems or experience any unexpected behavior when you tried it?

No,I did not try it.

Judging though from your answer I suppose it is OK.

I will proceed and test it…

1 Like

Each script should be wrapped in its own IIFE.

Should you want part of the code in a script to have a scope independent of the rest of the script then it too can be wrapped in an IIFE.

With your scripts all correctly placed at the bottom of the page document.ready does nothing except slow the running of the scripts and so is best removed.

You could, but I can’t think of a valid use for it, inside the ready function variables declared with var are already scoped to that function so won’t create globals.

$(function() {
  var scoped = true;
})

An IIFE is valid anywhere so you can do it though.

$(function() {

  (function() {
    console.log('yes');
  })();

})