Let’s take a step back here and fix some more fundamental misconceptions before talking about IIFEs again. First, there is no way in JavaScript to “cut off linkages” to the global environment. All functions have their own scope that contains variables defined in their blocks as well as a reference to the environment they were created in. If your code tries to access a property that is not defined in a function, JS will go up the chain to the next environment to look there. This will continue until either a value is found or the global object has been checked and nothing found.
In your first example, you’re creating three different variables called x.
var x = 23; // First variable
function test(x) { // Second variable
var x = 3; // Third variable
console.log(x); // "3"
}
If you wrap this in an IIFE, nothing will change.
var x = 23; // First variable
(function test(x) { // Second variable, always undefined because it will never be passed anything
var x = 3; // Third variable
console.log(x); // "3"
})()
Your first variable is never accessed. This is because there’s already a variable x within the function’s scope, so there’s no reason to check outside of it. If you remove all of the x variables in your function, it will access the globally defined x.
var x = 23;
function test(y) {
var z = 3;
console.log(x); // "23"
}
Again, nothing changes if we use an IIFE.
Let’s clear up something else. An IIFE isn’t anything special. It’s just a function. All functions create a closure of variables from the environment they are executed in, but functions cannot access the scope of functions that they’ve called.
function test() {
var x = "Can you see me?";
console.log("I'm a test!");
}
test();
console.log(x); // ERROR
(function() {
var x = "Can you see me?";
console.log("I'm also a test!")
})();
console.log(x); // ERROR
There’s really no difference between these two (they get called at different times, but it’s not important right now). An IIFE is just another way of writing a function. Since all functions in JavaScript create their own lexical environments, this has often been used to cache values that may change, such as in a for loop.
for(var i = 0; i < users.length; i++) {
fetch(url)
.then(response => response.json())
.then(userData => {
var myUser = users[i]; // This will always the be last user in the array
// Broken app :(
}
}
for(var i = 0; i < users.length; i++) {
(function() {
var storedUser = users[i];
fetch(url)
.then(response => response.json())
.then(userData => {
// This still has access to the storedUser variable
// App works!
})
})()
}
We don’t need to do this as much now that we have the let and const keywords, but exploiting closures can still be a useful tool.
The main point that I want to get across is that IIFEs do not keep the global scope out of your functions, they keep your functions out of the global scope. Keep that in mind and re-read @lionel-rowe’s posts. I think that should answer all of your questions.