- 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
var
was the primary way to declare variables in JavaScript, and it is still widely used.- Variables declared with
var
have function-level scope, meaning they are accessible within the function they are declared in, or globally if declared outside of any function. var
variables can be redeclared and updated throughout the program.var
declarations 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),
let
provides a more predictable way to declare variables compared tovar
. - Variables declared with
let
have block-level scope, meaning they are accessible only within the block they are declared in. - Unlike
var
,let
variables cannot be redeclared in the same scope, but they can be updated. let
declarations 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,
const
is used to declare variables that cannot be reassigned. const
variables have block-level scope likelet
.- While the value of a
const
variable cannot be reassigned, if it's an object or array, its properties or elements can still be modified. const
declarations 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
var
variables have function-level scope.let
andconst
variables have block-level scope.- Variables declared with
var
are hoisted to the top of their function scope, whilelet
andconst
variables are not hoisted. - Using
let
andconst
provides 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
var
are hoisted and initialized withundefined
, variables declared withlet
andconst
are not initialized until their actual declaration, leading to atemporal dead zone
where 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
var
are initialized withundefined
, and variables declared withlet
andconst
remainuninitialized
until their declaration, it's important to note that the variable declaration itself ishoisted
in 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
outside
is declared outside of any block and is accessible both inside and outside of the block without any issues. - The variable
inside
is declared usinglet
within a block. When JavaScript reaches theconsole.log(inside)
statement, it recognizes thatinside
has been declared but not yet initialized. - Since
inside
is 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
condition
is true, JavaScript will attempt to accessx
before its declaration inside theif
block, resulting in aReferenceError
due to the TDZ. - If the
condition
is false,y
is declared and initialized within the else block. However, sincey
is declared usinglet
, it is nothoisted
outside of theelse
block, so trying to access it outside of the block results inundefined
.
string
, number
, boolean
, object
, array
)
Data Types (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, eithertrue
orfalse
.
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]
arithmetic
, comparison
, logical
)
Operators (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
if-else statements
, switch statements
, loops
)
Control Flow (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)