top of page

JavaScript Overview — Declaring And Using Variables

Whether you're just learning how to code, an expert brushing up on the basics, or a founder trying to communicate better with a technical team, we're diving into declaring and using variables in JavaScript – courtesy of the Remedy engineering team.


We'll walk through Scope, Hoisting, Bindings, Temporal Dead Zones, and Functional Declarations vs Class Declarations. Keep an eye out for resources throughout the piece in case you want to explore any of the topics further.


Scope

"Scopes are like buckets, and variables are like marbles you put into those buckets."You Don’t Know JS Yet

A scope is a set of rules that controls how references to variables work. They're all about the visibility of variables in your code and control which variable can be used where. Each scope can “look out” into the scope around it. Scopes are static and contain a fixed set of variables available at a given moment or location.


JavaScript has three types of scope: Global Scope, Function Scope, Block Scope.

Global Scope is the scope that contains, and is visible in, all other scopes.


Until ES6, the newest version of JavaScript, function scope was the only form of scope in JS; all variable and function declarations followed function scope rules. Block scope was introduced in ES6 and is used only by the variables declared with the new variable declaration keywords let and const.

Function scope in JavaScript is created inside of functions. When a function is declared, a new scope block is created inside the body of that function. Variables that are declared inside the new function scope cannot be accessed from the parent scope, but the function scope has access to all variables in the parent scope.


Parent scope is the block of code the function is defined in. It is not the block of code in which the function is called.


To create a variable with function scope, we must declare the variable with the var keyword.

Block scope in JavaScript is created with curved brackets ( {} )


A pair of curbed brackets can be placed anywhere in the code to define a new block scope. If statements, loops, functions, and any other curved bracket pairs will have their own block scope. This includes floating curved bracket pairs not associated with a keyword (if, for, etc).


Hoisting

JavaScript Hoisting refers to when an interpreter moves the declaration of functions, variables, or classes to the top of their scope, prior to execution of the code.


Hoisting is a feature that is based on two ‘phases’ of code execution:

  • Compile Phase (where the code is analyzed)

  • Execution Phase (where the code is executed)

JavaScript allocates memory for all variables and functions defined in the program before execution, but only hoists declarations, not initializations.


Declaration → Initialization/Assignment → Usage


More:


Bindings

To catch and hold values, JavaScript provides a binding, or variable.


let myName = “Joe”


In this sentence, the keyword let indicates that we are going to define a binding. It is followed by the name of the binding and if we want to immediately give it a value, by = operator and an expression. This binding is called myName and is used to take hold of the Joe string. Bindings don’t contain values, they grab them.


After a binding has been defined, its name can be used as an expression. If we define a binding without giving it a value, there is nothing to grab, so we get the value undefined. JavaScript systems always put a number of useful standard bindings into your environment, like alert() and console.log().


Each binding has a scope – the part of the code in which the binding is visible. A variable or binding can only be used in its scope and/or any nested scope.


For bindings defined outside of any function or block, the scope is the whole program — you can refer to these global bindings wherever you want.


However, bindings created for specific function parameters or declared inside a function can be referenced only in that function, so they are known as local bindings.


More:


Var, let, and const

Basic JavaScript uses the keyword var for variable declaration, but ECMAScript 6 (ES6/ES2015) introduced the two keywords let and const that support the declaration of block scope local variables. This means variables will be confined to the scope of the block they are defined in, such as an if statement or for loop, and will not be accessible outside of the opening and closing curly braces of the block.


This is contrary to var declarations, which are accessible outside of the blocks they are defined in.



The difference between the two variables let and const is that a const declaration is, as the name implies, constant — a read-only reference to a value. This does not mean the value is immutable, just that the variable identifier cannot be reassigned.


Note: Since a hoisted variable that’s been declared with var can be used before it is declared, we have to be careful to not use that variable before it has been assigned a value. If a variable is accessed before it has been assigned a value, it will return the value as undefined.


This can cause problems, especially if variables are used in the global scope.


More:


Temporal Dead Zone (TDZ)

Temporal Dead Zone (TDZ) is the term used to describe the state where variables are unreachable. They are in scope, but they aren’t declared. Variables declared by either let const have TDZs. Variables declared with both let const have block scope. When a variable is declared with block scope, it does NOT have the same variable hoisting as variables that are created in function scope.


Block scope variables are not hoisted to the top of the scope and therefore cannot be accessed until they are declared. This means variables that are created with block scope are subject to the Temporal Dead Zone (TDZ).


The TDZ is the period between when a scope is entered and when a variable is declared. It ends when the variable is declared rather than assigned.


If a variable is accessed inside the Temporal Dead Zone, a runtime error will be thrown. This is important because it allows our code to be built more robustly with fewer semantic errors arising from variable declaration.


Let’s look at an example:



If we run this code we will get a ReferenceError. Why? Because when we declare the variable const x = 5 in block scope {}, we create TDZ for x that we use in console.log(x). You can find more examples here.


Global Object

Let’s look at an example of a global object:



ES6 introduced a distinction for JavaScript global object window in browsers and global in Node.js

  • All properties of the global object are global variables. In global scope, the following declarations create such properties var declarations and Function declarations.

  • There are now also global variables that are not properties of the global object. In the global scope, the following declarations create such variables:

let const class declarations. The environments for various variables form the following chain Module variablesGlobal variablesGlobal object


Function Declarations vs Class Declarations

Function declarations are block-scoped, like let; create properties in the global object (while in global scope), like var; and are hoisted: independent of where a function declaration is mentioned in its scope, it is always created at the beginning of the scope.


Class declarations:

  • are block-scoped.

  • don’t create properties on the global object.

  • are not hoisted.

The Review

JavaScript can feel daunting but breaking it down to the basics – like scope, bindings, and hoisting – helps. We reviewed the relationship among the three and how var, let, and const worked across them. After mastering these, we broadened our scope, looking at global objects, Temporal Dead Zones (TDZ), function declarations, and class declarations. You're now brushed up on the basics and ready to get started.




bottom of page