Front end Development Scope, Context, Hoisting & Closure - Vincentvanleeuwen/project-tech-2020 GitHub Wiki
Execution Context
The Global Execution Context is created before any code is executed, it will assign "this" to the window object. If you execute a function, a new execution context is created this is what they call the functional execution context. In every execution context "this" is applied. Execution Context actually just holds information about the surroundings in the function it's being executed in.
If you compare the global this with an inner function this, it'll return that they are in fact the same. The window contains the global object. If you'd like to use the global context, you can either call window or this in the global scope. It starts by creating all the variables and functions. Once it created these, it'll assign them to the name you've given it. e.g.:
let matches = require('./routes/matches');
It'll first create the require function. Once this has been created it'll assign it to the variable "matches". Therefore in the creation phase, matches will be undefined. Once the Global execution context executed, it won't be undefined anymore.
You can also assign this to a variable. So you can set the variable to a value that will be lost otherwise for later use. For example
var oldThis;
function dogs(breed) {
oldThis = this; // Saves the current this into a variable
this.breed = breed // Add a variable to the this object
getBreed = () => {
return `The dog is a ${this.breed}` // Refers to this.breed in the local scope
}
}
dogs('labrador');
Scope
Each scope has access to it's outer scopes, as far as to the global scope. This is referred to as the "Scope chain". The scope chain doesn't know anything about their siblings. Therefore if you define a variable in a function, and you put a function below that and try to access it, it'll return undefined. Inside the function it's called the local scope. All the variables you define here won't be accessible from outside the function. You can also put another function in a function. Within this function is the nested local scope.
const oneDog = "Bobby"; // The global scope!
function dogVariables() { // The local scope!
const allDogs = await getDogs(); // You won't be able to use this outside the function
console.log(oneDog) // Still works! Returns "Bobby"
function labradors() { // Nested local scope!
console.log(oneDog) // Still works! Returns "Bobby"
}
}
function catVariables() {
console.log(oneDog) // returns "Bobby"!
console.log(allDogs) // returns undefined because it's in the local scope of dogVariables.
}
dogVariables();
catVariables();
console.log(allDogs); // undefined!
Hoisting
In JavaScript all functions and variables are hoisted. Hoisting means that you can use a function or variable before it's defined, this is done by placing all the code starting with var or function into memory space. Let and const however won't be accessible. let will show "Cannot access variable before initialization" and const will show "Missing initializer in const declaration". Also during this the scope chain will be created, and lastly the value of this will be set to the default global namespace, AKA, the window object. They call this the creation phase. After the creation phase the execution phase starts. In the execution phase JavaScript will read each line of code. During this JavaScript allows each variable or function to access the memory space to add the values that have been set before the initial declaration of the variable or function. The act of saving the functions and variables in a so called memory space and making them available in the execution phase is called hoisting.
For example:
animal = "dog";
const animal;
console.log(animal) // returns "dog"
If you would like to be able to use a variable outside the function you can make use of Hoisting. By placing allDogs outside the function, without a definition, you can then set the variable within the function, and still use it outside the function.
let allDogs;
async function dogVariables(req, res, next) {
allDogs = await getDogs(); // You can now acces allDogs outside this function!!
const allMessages = await getMessages();
req.session.user = {email: req.body.email};
req.session.matches = Dog.dogMatches(allDogs, req.session.user);
req.session.allDogs = allDogs;
req.session.selected = Dog.selectedConversation(req.session.allDogs,req.session.user, 0);
req.session.messages = Message.getMessages(allMessages, req.session.user.email, req.session.selected.email);
next();
}
dogVariables();
console.log(allDogs) // All the dogs!
Closures
A closure is actually just a function bundled with another function. With closures you can access the outside scopes from the inner function. Closures are created each time a function is executed. Lexical scoping is what they use for closures. With lexical scoping you can only access your parents variables, but not the other way around. Read the comments for further explanation.
const dogs = []; // This is the global scope. You can access this constant everywhere.
console.log(dogs) //Returns an empty array
function dogVariables() { // The function within the global scope.
// Get dogs collection & messages collection from mongoDB
dogs = await Dog.getDogs(); // This is the local scope. This can only be read within the function
// Set the session for this user if undefined
function setSession() { // This is the closure. It's the function within dogVariables();
console.log(dogs) // returns an array with dogs ['dog 1', 'dog 2', 'dog 3']
}
}
console.log(dogs) // Empty array
dogVariables();
console.log(dogs) // returns an array with dogs ['dog 1', 'dog 2', 'dog 3']
Sources
McGinnis, T. (2018, 16 October. ). “The Ultimate Guide to Hoisting, Scopes, and Closures in JavaScript” TylerMcGinnis, at https://tylermcginnis.com/ultimate-guide-to-execution-contexts-hoisting-scopes-and-closures-in-javascript/. at date 3 June, 2020.
MDN contributors. (May 31, 2020). "Closures", at https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures at date 23 June, 2020.
Gillus, T. (December 13, 2015). "JavaScript Variables and Functions are Hoisted Prior to Execution" at http://tramaine.me/blog/javascript-variables-and-functions-are-hoisted-prior-to-execution#:~:text=All%20JavaScript%20code%20executes%20in,and%20functions%20into%20memory%20space. at date 23 June, 2020.
Ogura, M. (Aug 17, 2017). "JS Demystified 03— Scope" at https://codeburst.io/js-demystified-03-scope-f841ecad5c23 at date 23 June, 2020.
Ogura, M. (Aug 24, 2017). "JS Demystified 04 — Execution Context" at https://codeburst.io/js-demystified-04-execution-context-97dea52c8ac6#:~:text=In%20JavaScript%2C%20execution%20context%20is,starts%20to%20execute%20any%20code. at date 23 June, 2020.