A JavaScript Fundamentals Cheat Sheet: Scope, Context, and “this”
Tags: javascript, beginners
Published: 2019-07-05 03:20:13

Scope

Scope refers to where a variable can be accessed within a program. Some variables can be accessed from anywhere within a program (global scope), while others have a more limited context (function and block scopes).

When we are not in a function or a block (code grouped between two curly braces {}), we are in the global scope. Any variable declared here can be accessed anywhere else within the global scope, but also within a function or a block.

Variables can be declared in function scope, which exists within a function. These variables are accessible to any code within that function, including additional blocks, but they are not accessible within the global scope.

//This variable is declared in the global scope
let user = "Alex";

    function greetUser(){
//This variable is declared in the function scope
       let greeting = "Hello, ";

//This return can access both variables declared within its 
scope(function), as well as global scope variables
       return greeting + user;
    }

Block scope is observed by let & const (the variable declarations introduced with ES6), but not by var. As such, var shouldn’t be used when declaring variables in block scope (or in most situations). Variables declared (with let or const) within block scope will only be accessible within that scope, and not within any outer scopes. Block scopes however have access to all variables declared in the global scope, as well as within any containing functions.

Variables within a block will act the same as they would if defined within a function, meaning they can not be re-declared, and const variables can not be redefined, within that block. However, because these variables are only scoped within this block, a variable of the same name could be declared within the containing function without necessarily causing problems.
Context

Context refers to an object, and it is relevant when executing a function. Objects have properties and methods that can be accessed using ‘this’, and knowing the context of a function is important so that we understand what the value of ‘this’ will be after executing a function.

Generally, the context of a function will refer to the object it is being called on. This is true for functions that are nested within other functions on an object, and for constructor functions that are used when instantiating objects. When a function is not called on an object, the context is the global, meaning ‘this’ will refer to the window object.
“this”

Context is important because it highlights the object that will be passed to the value of the ‘this’ property that we can then use when executing a function. This allows us to access the values of the object within the function, letting us write functions that may be reused by multiple objects, keeping our code DRY.

When we have an object with functions stored as an attribute value, ‘this’ is passed implicitly to the function, because the function is defined as part of the objects declaration, and so the function will always know how it is being invoked. In the example below, calling user.greeting(), implicitly sets the value of ‘this’ to the user (the object the function is being called on).

const user = {
   name: "Alex",
   age: 26,
//'this' value will be passed to the function implicitly as it is 
defined as part of the object variable
   greeting(){
       "My name is ${this.name}, and I am ${this.age} years old.";
   }
}

Bind, call, and apply are built in functions, introduced in ES5, that allow you to pass a parameter of the context object that should be used for ‘this’. They are helpful when calling a function that is defined within the global scope on an object, or when you are using an built-in JavaScript method (such as reduce, filter, map, etc.) and need to explicitly state the context so that the function does not return a TypeError.

function greeting() {
    console.log(`Hello, ${this.name}!`);
}
 
const user = { 
   name: 'Alex' 
}
 
//Passing the object through call ensures that the greeting function will have access to the correct object through 'this' 
greet.call(user);

Constructors create an object and then use that newly instantiated object as the ‘this’ value, allowing it to then set values to attributes.

class Game {
//The context within a constructor is the object instantiated, allowing 
us to access the new object with 'this', and set its attribute values
	constructor(id, name, release_year, consoles, review = ""){
		this.id = id;
		this.name = name;
		this.release_year = release_year;
		this.consoles = consoles;
	}
}

Arrow functions, introduced in ES6, do not have an implicit “this”, and can be used in places where we might otherwise have needed a bind, call, or apply method. They will look at their containing function or parent to determine the value of ‘this’.

The final way that ‘this’ can be defined is when a function is written in the global scope but uses ‘this’ and does not make use of bind, call, or apply when invoking the function. In this instance, the value of ‘this’ will be the window object, and will return as undefined. 

**This article was originally posted on my blog at http://alexandrafren.com/2019/02/28/a-javascript-fundamentals-cheat-sheet-scope-context-and-this/