About the series
Core JavaScript is a series I'm writing that covers, as the name suggests, some of the core principles of JavaScript. It originally started as a study or reference material for myself, but I decided to share it with the community in the hopes that it will prove useful for others.
This series is intended for beginner JavaScript developers or more experienced developers in need of a refresher. I have a few topics planned out already, but I would love to hear from you if there are any topics, in particular, you would be interested to read about!
You might recall that in a previous article, we came across the concept of scope in JavaScript. In short, scope represents the section of code in which a variable is accessible. There are a few different types of scope in JavaScript:
Global scope
Module scope
Function scope
Block scope
Let's go through each of them to see how they work.
Global scope
The global scope exists outside of any functions. Variables declared in the global scope are called global variables, and they can be accessed anywhere in the code.
const name = 'Jane'; // Global variable, in global scope
function greet() {
console.log(`Hello, ${name}!`); // Hello, Jane!
}
Note: If you assign a value to a variable that has not yet been declared, it automatically becomes a global variable, unless you are using strict mode.
function greet() {
name = 'Jane';
console.log(`Hello, ${name}!`); // Hello, Jane!
}
Module scope
With the introduction of modules in ES2015 also came the concept of module scope. Consider the following module, greeting
:
// greeting.js
const name = 'John';
console.log(`Hello, ${name}!`);
Let's import the module into a different file and try to access name
:
import '../greeting.js'
console.log(name);
This will throw an error, because name
is not accessible outside its module, greeting
, unless it is exported.
Function scope
In JavaScript, each function creates its own scope. Variables declared within a function scope are called local variables, and they can only be accessed within the function they have been declared in.
function greet() {
const name = 'John'; // Local variable, in function scope
console.log(`Hello, ${name}!`);
}
greet(); // Hello, John!
console.log(name); // ReferenceError: name is not defined
Block scope
Block scope is the scope that exists within a pair of curly brackets { }
. Variables declared within a block scope are only accessible within that scope.
if (true) {
const name = 'John'; // Block-scoped variable
console.log(`Hello, ${name}!`); // Hello, John!
}
console.log(name); // ReferenceError: name is not defined
Note: var
variables behave differently in this scenario - they are not block scoped! var
variables can be accessed outside of the block scope (but not outside of the function scope!).
if (true) {
var name = 'John'; // Block-scoped variable
console.log(`Hello, ${name}!`); // Hello, John!
}
console.log(name); // John
Scope nesting
In JavaScript, scopes can be nested, meaning that a scope can exist inside another scope.
function greet() {
// Function scope of the greet function
const name = 'John';
if (name === 'John') {
// Block scope of the if-statement
const greeting = 'Hello';
console.log(`${greeting}, ${name}!`); // Hello, John!
}
console.log(greeting); // ReferenceError: greeting is not defined
}
The scope of the greet
function is called the outer scope, and the scope of the if
statement is called the inner scope. The important takeaway here is that variables declared in the outer scope can be accessed in the inner scope, but variables declared in the inner scope cannot be accessed in the outer scope.
Scope chain
Whenever you try to access a variable within your code, the search process begins from the local scope of the function you are calling. If the variable does not exist in the local scope, the search moves on to the outer scope (e.g. the scope of a parent function) until it reaches the outermost scope of the code - the global scope. This path that the code goes down in order to find the variable is known as the scope chain. If the variable is not found anywhere along the way, you will get a ReferenceError.
Practice
What are the outputs of these code snippets?
function greet() { let name = 'John'; console.log(`Hello, ${name}!`) } name = 'Jane'; greet(); console.log(`Hello, ${name}!`);
Answer:
Hello, John! Hello, Jane!
Reason: The
name
inside of thegreet
function is a local variable, so it cannot be changed from outside of the function.name = 'Jane';
essentially creates a new global variable.let name = 'John'; if (true) { let name = 'Jane'; } console.log(name);
Answer:
John
Reason: The
name
variable with the valueJane
is created within the block scope of theif
statement. Therefore, it cannot be accessed from the global scope. Instead,name
will have the value given to it in the global scope, which isJohn
.let name = 'John'; if (true) { var name = 'Jane'; } console.log(name);
Answer:
SyntaxError: Identifier 'name' has already been declared
Reason:
var
does not follow the same rules aslet
andconst
- its declaration will be global despite being placed inside of theif
block. Therefore, the code will throw an error asname
has already been declared in the global scope.
Thank you for reading this article in my Core JavaScript series! If you found this useful, if you have anything to add, or if I made any mistakes - I would love to hear from you! I'm also very open to suggestions for future topics for the series. 😊
Expect to see the next part soon. Thanks and see you there!