- Published on
Core JavaScript Concepts
Table of Contents
Variables in JavaScript
Variables are used to store data values. JavaScript has three ways to declare a variable: var, let, and const.
var
varwas the primary way to declare variables in JavaScript, and it is still widely used.- Variables declared with
varhave function-level scope, meaning they are accessible within the function they are declared in, or globally if declared outside of any function. varvariables can be redeclared and updated throughout the program.vardeclarations are hoisted to the top of their scope during runtime, which can sometimes lead to unexpected behavior.
Example:
var x = 100
console.log(x) // Output: 100
function exampleVar() {
if (true) {
var x = 100
}
console.log(x) // Output: 100
}
exampleVar()
let
- Introduced in ECMAScript 6 (ES6),
letprovides a more predictable way to declare variables compared tovar. - Variables declared with
lethave block-level scope, meaning they are accessible only within the block they are declared in. - Unlike
var,letvariables cannot be redeclared in the same scope, but they can be updated. letdeclarations are not hoisted to the top of their scope, which helps prevent certain types of bugs.
Example:
let x = 100
if(true){
lex x = 50
console.log(x) // Output: 50
}
console.log(x) // Output: 100
function exampleLet() {
if (true) {
let y = 100
console.log(y); // Output: 100
}
// console.log(y); // Error: y is not defined
}
exampleLet()
const
- Introduced in ES6,
constis used to declare variables that cannot be reassigned. constvariables have block-level scope likelet.- While the value of a
constvariable cannot be reassigned, if it's an object or array, its properties or elements can still be modified. constdeclarations are not hoisted and must be initialized with a value at the time of declaration.
Example:
const x = 100
if (true) {
const x = 50
console.log(x) // Output: 50
}
console.log(x) // Output: 100
function exampleConst() {
if (true) {
const y = 100
console.log(y) // Output: 100
// y = 50; // Error: Assignment to constant variable
}
// console.log(y); // Error: y is not defined
}
exampleConst()
Scope in JavaScript
Scope refers to the visibility and accessibility of variables in different parts of your code. In JavaScript, there are mainly two types of scope:
-
Global Scope: Variables declared outside of any function or block have global scope, meaning they are accessible from anywhere within the JavaScript code.
-
Local Scope: Variables declared within a function or block have local scope, meaning they are accessible only within that function or block.
Scope with var
Variables declared with var have function-level scope. This means they are accessible throughout the function in which they are declared, including within nested blocks. However, they are not accessible outside of that function.
Example:
function varScopeExample() {
if (true) {
var x = 10
console.log(x) // Output: 10
}
console.log(x) // Output: 10
}
varScopeExample()
// console.log(x); // Error: x is not defined
In the above example, x is accessible both inside and outside of the if block because it is declared with var within the function varScopeExample(). However, it is not accessible outside of the function.
Scope with let and const
Variables declared with let and const have block-level scope. This means they are accessible only within the block in which they are declared, including nested blocks, but not outside of that block.
Example:
function letConstScopeExample() {
if (true) {
let y = 20
const z = 30
console.log(y) // Output: 20
console.log(z) // Output: 30
}
// console.log(y); // Error: y is not defined
// console.log(z); // Error: z is not defined
}
letConstScopeExample()
In this example, y and z are declared within the if block using let and const, respectively. Therefore, they are only accessible within that block. Attempting to access them outside of the block would result in an error.
Summary
varvariables have function-level scope.letandconstvariables have block-level scope.- Variables declared with
varare hoisted to the top of their function scope, whileletandconstvariables are not hoisted. - Using
letandconstprovides more predictable scoping behavior and helps prevent certain types of bugs, especially in larger codebases.
Hoisting
Hoisting is a JavaScript mechanism where variable and function declarations are moved to the top of their containing scope during the compile phase before the code execution. This means that no matter where functions and variables are declared within a scope, they are moved to the top of their scope, allowing them to be used before they are actually declared in the code.
Hoisting with var
When variables are declared using var, they are hoisted to the top of their function scope. However, only the variable declaration is hoisted, not the initialization.
console.log(x) // Output: undefined
var x = 10
The above code is interpreted by JavaScript as:
var x
console.log(x) // Output: undefined
x = 10
Hoisting with let and const
Variables declared using let and const are also hoisted to the top of their block scope, but they are not initialized until the actual declaration is encountered in the code. This is known as the temporal dead zone.
// console.log(y); // Error: Cannot access 'y' before initialization
let y = 20
In the above code, even though y is declared using let, trying to access it before its declaration results in an error because it is not yet initialized.
Hoisting Considerations
varare hoisted and initialized withundefined, variables declared withletandconstare not initialized until their actual declaration, leading to atemporal dead zonewhere accessing them results in a ReferenceError.- It's generally recommended to declare variables at the top of their scope to improve code readability and avoid potential hoisting-related issues.
Hoisting with Functions
Function declarations are also hoisted to the top of their containing scope.
foo() // Output: "Hello, world!"
function foo() {
console.log('Hello, world!')
}
In the above code, the function foo is called before its declaration, but it still works because function declarations are hoisted to the top.
Hoisting with Function Expressions
Function expressions are not hoisted in the same way as function declarations. Only the variable declaration is hoisted, not the function initialization.
// console.log(add(2, 3)); // Error: add is not a function
var add = function (a, b) {
return a + b
}
console.log(add(2, 3)) // Output: 5
In the above code, attempting to call add before its declaration results in an error because the function expression is not hoisted.
Hoisting with Class Declarations
Class declarations are hoisted like function declarations, meaning they are moved to the top of their scope.
const car = new Car() // Output: "I am a car!"
class Car {
constructor() {
console.log('I am a car!')
}
}
In the above code, the Car class is accessed before its declaration, but it still works because class declarations are hoisted to the top.
Hoisting Caveats
- Arrow Functions: Arrow functions are not hoisted because they are essentially function expressions. Therefore, trying to access them before their declaration will result in a reference error.
// console.log(add(2, 3)); // Error: add is not defined
const add = (a, b) => a + b
console.log(add(2, 3)) // Output: 5
- Variable Initialization:While variables declared with
varare initialized withundefined, and variables declared withletandconstremainuninitializeduntil their declaration, it's important to note that the variable declaration itself ishoistedin all cases.
console.log(x) // Output: undefined
var x
Temporal Dead Zone (TDZ)
The Temporal Dead Zone (TDZ) is a period in JavaScript code where a variable declared with let or const exists but cannot be accessed or referenced before its declaration. This happens because variables declared with let and const are hoisted to the top of their containing block scope, but they are not initialized until the actual declaration statement is reached. Accessing such variables during the TDZ results in a ReferenceError.
// No TDZ Example
let outside = 'outside TDZ'
{
console.log(outside) // Output: 'outside TDZ'
// The variable `outside` is accessible here because it's outside of any TDZ.
}
// TDZ Example
{
console.log(inside) // Output: ReferenceError: Cannot access 'inside' before initialization
let inside = 'inside TDZ'
}
- The variable
outsideis declared outside of any block and is accessible both inside and outside of the block without any issues. - The variable
insideis declared usingletwithin a block. When JavaScript reaches theconsole.log(inside)statement, it recognizes thatinsidehas been declared but not yet initialized. - Since
insideis still in its TDZ, attempting to access it results in aReferenceError.
let condition = true
if (condition) {
console.log(x) // Output: ReferenceError: Cannot access 'x' before initialization
let x = 'inside if'
} else {
let y = 'inside else'
console.log(y) // Output: undefined
}
- If the
conditionis true, JavaScript will attempt to accessxbefore its declaration inside theifblock, resulting in aReferenceErrordue to the TDZ. - If the
conditionis false,yis declared and initialized within the else block. However, sinceyis declared usinglet, it is nothoistedoutside of theelseblock, so trying to access it outside of the block results inundefined.
Data Types (string, number, boolean, object, array)
string: Represents textual data, enclosed within single or double quotes.
let greeting = 'Hello, World!'
number: Represents numeric data, both integers and floating-point numbers.
let age = 25
let pi = 3.14
boolean: Represents a logical value, eithertrueorfalse.
let isLogged = true
let hasPermission = false
object: Represents a collection of key-value pairs. Keys are strings, and values can be of any data type.
let person = {
name: 'Rajnish',
age: 30,
isStudent: false,
}
array: Represents an ordered collection of elements, which can be of any data type.
let colors = ['red', 'green', 'blue']
let numbers = [1, 2, 3, 4, 5]
Operators (arithmetic, comparison, logical)
Arithmetic Operators: Used to perform arithmetic operations like addition, subtraction, multiplication, division, etc.
let a = 110
let b = 50
let sum = a + b // Addition
let difference = a - b // Subtraction
let product = a * b // Multiplication
let quotient = a / b // Division
Comparison Operators: Used to compare values and return a boolean result.
let x = 10
let y = 5
console.log(x > y) // Output: true
console.log(x === y) // Output: false
Logical Operators: Used to combine or manipulate boolean values.
let isLogged = true
let isAdmin = false
console.log(isLogged && isAdmin) // Output: false
console.log(isLogged || isAdmin) // Output: true
Control Flow (if-else statements, switch statements, loops)
if-else statements: Used for conditional execution of code.
let age = 18
if (age >= 18) {
console.log('You are an adult.')
} else {
console.log('You are a minor.')
}
switch statements: Used to perform different actions based on different conditions.
let day = 'Monday'
switch (day) {
case 'Monday':
console.log('Today is Monday.')
break
case 'Tuesday':
console.log('Today is Tuesday.')
break
default:
console.log("It's not Monday or Tuesday.")
}
Loops: Used to execute a block of code repeatedly.
// for loop:
for (let i = 0; i < 5; i++) {
console.log(i)
}
// while loop:
let i = 0
while (i < 5) {
console.log(i)
i++
}
// do-while loop:
let i = 0
do {
console.log(i)
i++
} while (i < 5)