Tricky Parts of JavaScript II?-?Scoping, Hoisting & `const`?Keyword
Theodora Gyambrah
Passionate Software Engineer | Project Manager | Blockchain Developer | Engineering dreams - one line of code at a time
This is the sequel to a previous article which we tackled the intricacies of the various data types and their behavior with the assignment operator. We also uncovered the tricky aspects of equality operators. If you missed it, you can catch up here.
Now, let’s dive right into the next chapter of our JavaScript exploration!
1. Scoping
In JavaScript, scoping determines where in your code a particular variable, function, or identifier is accessible. There are two fundamental types of scope:
Note: There is also the concept of lexical or static scoping in JS which is beyond the scope of this article.
Now let’s explore how local scoping can be tricky with the var, const and let keywords used for variable declarations:
// Example 1
function scopeExample() {
if (true) {
var x = 10;
}
console.log(x); // 10
}
scopeExample();
// Example 2
function scopeExample() {
if (true) {
let y = 20;
}
console.log(y); // ReferenceError: y is not defined
}
scopeExample();
// Example 3
function scopeExample() {
if (true) {
const z = 20;
}
console.log(z); // ReferenceError: z is not defined
}
scopeExample();
Let’s delve into each example to understand the behaviors seen above.
Example 1?—? var(Function Scope)
In this example, the variable x is declared using var, which is function-scoped. This means that the variable is accessible throughout the entire function, even though it was declared inside the if block. Hence, the console.log(x) statement outside the if block successfully logs the value of x due to this scoping behavior.
Example 2?—? let(Block Scope)
In this case, the variable y is declared with let, which has block scope. Variables with block scope are limited to the block (in this case, the if block) where they are defined. Attempting to access y outside the block results in a ReferenceError because it is not defined in that scope.
Example 3— const(Block Scope)
Similar to Example 2, the variable z is declared using const, which also has block scope. The attempt to log z outside the if block results in a ReferenceError because z is not defined in that scope.
2. Hoisting
Hoisting is a behavior in JavaScript where variable and function declarations are moved to the top of their containing scope during the compilation phase. This means that you can use variables and functions in your code before they are declared.
There are two main types of hoisting in JavaScript: variable hoisting and function hoisting.
Now, let’s examine some tricky aspects of hoisting with the code snippet below:
// Example 1
console.log(a); // undefined, not error
var a = 10;
// Example 2
console.log(b); // ReferenceError: b is not defined
let b = 20;
// Example 3
console.log(c); // ReferenceError: c is not defined
const b = 30;
// Example 4
foo(); // "Hello, world!"
function foo() {
console.log("Hello, world!");
}
Example 1— Hoisting with?var
In this example,
Examples 2 & 3— Hoisting with let and?const
In these examples,
领英推荐
Example 4— Function?Hoisting
In this example,
Note: Hoisting of Function Expressions
When using a function expression assigned to a variable, the declaration is hoisted, but the assignment is not. This behavior contrasts with function declarations, where the entire function is hoisted.
Let’s look at an example:
//Function Expressions with `var`
foo(); // TypeError: foo is not a function
var foo = function() {
console.log("Hello, world!");
};
bar(); // TypeError: bar is not a function
var bar = () => {
console.log("Hello, world!"); // ES6 Arrow Function
};
//Function Expressions with `let`
foo(); // ReferenceError: Cannot access 'foo' before initialization
let foo = function() {
console.log("Hello, world!");
};
bar(); // ReferenceError: Cannot access 'bar' before initialization
let bar = () => {
console.log("Hello, world!"); // ES6 Arrow Function
};
//Function Expressions with const
foo(); // ReferenceError: Cannot access 'foo' before initialization"
const foo = function() {
console.log("Hello, world!");
};
bar(); // ReferenceError: Cannot access 'bar' before initialization"
const bar = () => {
console.log("Hello, world!"); // ES6 Arrow Function
};
In this code snippet,
3. const?Keyword
The use of “const” in JavaScript declares a variable that cannot be reassigned after its initialization.
Let’s consider the code snippet below to examine some tricky aspects of the “const” keyword:
// Example 1
const gravity = 9.8;
gravity = 9.81; // TypeError: Assignment to constant variable.
// Example 2
const planet = "Earth";
planet = "Mars"; // TypeError: Assignment to constant variable.
// Example 3
const colors = ["red", "green", "blue"];
colors.push("yellow");
console.log(colors); // ["red", "green", "blue", "yellow"]
//Example 4
const person = { name: "Fred", age: 25 };
person.age = 26;
console.log(person); // { name: "Fred", age: 26 }
Before delving into the examples provided, a brief revisit to our previous article (link here) in this series would serve as a helpful reference. This will remind us that the variables gravity and planet in examples 1 and 2 respectively belong to the category of primitive data types. Similarly, the variables colors and person in examples 3 and 4 fall under the reference data types category.
Now, let’s examine each category in the code snippet above:
Example 1 & 2?—?Immutability for Primitive Values
In these examples, the attempt to reassign the constant variables gravity and planet resulted in a TypeError. This error occurs because the const declaration ensures that the variable remains constant and cannot be reassigned after initialization.?
Example 3 & 4— Immutability for Reference Types
In these examples, despite the use of the const keyword, the content of arrays or objects can be modified. This is because, for reference data types, const doesn't impose immutability on the contents; it merely prevents reassignment of the variable.?
As such, attempting to reassign the entire array or object will result in an error:
// Example 3
const colors = ["red", "green", "blue"];
colors = ["orange", "purple", "pink"]; // TypeError: Assignment to a constant variable.
// Example 4
const person = { name: "Alice", age: 25 };
person = { name: "Bob", age: 30 }; // TypeError: Assignment to a constant variable.
In these cases, the attempt to reassign a new value to the entire variable colors and person throws an error. const ensures that the variable itself cannot be reassigned but allows for modification of the contents.
In Conclusion,
We’ve uncovered some tricky parts of JavaScript, from understanding scoping and hoisting to navigating the unique traits of const variables. Exploring the subtleties of variable visibility and the delicate balance between constancy and mutability equips you to navigate the challenges and optimize your JavaScript code.
Stay tuned for more insights into the ever-evolving world of software engineering!
Expert Passionné d'Anglais???
1 年Happy to read your article Theodora.