Let's warm up with something pretty easy!
Short for "enclosure"
Closures are all about scope (or context) control
They allow you to avoid the use of global variables.
Why are global variables undesirable?
In the browser, all of the JavaScripts running on a page share the same global scope.
That global scope is the named the "window" object
Your *.js file is probably not going to be the only one on the page
If you have 10 scripts, and they all use a global variable called "config", they will conflict and the value of "config" will be difficult to pinpoint at any given time during page life.
To create a closure, you simply write a function body.
Inside the function body you have created a new scope.
Scope, simply put, is all of the references (variables, function names) that are available for use.
This inner scope can access the outer scope references.
Functions are considered "first-class citizens" in JavaScript.
They can be passed around and assigned to variables just like any other type (like a number or string).
This is an extremely important language feature!
Within any function, variables defined using the "var" keyword will be private to the scope of that function (ie. not accessible to the outer scope)
Since a closure is quite literally a function, this is how closures control scope.
If you've ever used the "var" keyword inside a function, you've technically used the power of closures already!
So since closures are functions, how can one avoid using 0 global references within a *.js file? Won't your closure function need at least 1 reference - for itself?
There is a nifty trick called IIFE which stands for "immediately invoked function expression" (you can just refer to it as a self-executing function though for brevity)
This is simply a closure that executes itself immediately.
Remember how closures are functions?
If you're just using standard functions, that function would need to be called from somewhere in the *.js file (or by another script, since the global scope is all shared)
This is not so with IIFEs!
All of the global scope is available inside of the closure. (Otherwise you couldn't use the "window" object without having passing it in your function as an argument each time).
By default, everything inside the closure is private unless you are referencing global scope.
If you need access to functions or other types that are "private" inside of your closure scope, there are ways of exposing them as "public"
This enables a simple namespacing mechanism to be introduced to the language
It also means we can write safe, modular JavaScript code that can't conflict with other code sharing the same memory and global scope even if we have no idea what that other code does.