Master JavaScript: A Complete Guide
Table of contents
- Chapter 1: Introduction to JavaScript
- Chapter 2: JavaScript Basics
- Chapter 3: Control Structures in JavaScript
- Chapter 4: Functions in JavaScript
- Chapter 5: Objects in JavaScript
- 1. Creating Objects
- 2. Accessing Object Properties
- 3. Adding and Modifying Properties
- 4. Removing Properties
- 5. Object Methods
- 6. this Keyword
- 7. Nested Objects
- 8. Object Destructuring
- 9. Checking for Properties
- 10. Iterating Over Object Properties
- 11. Object.assign()
- 12. Object.keys(), Object.values(), and Object.entries()
- Summary of Objects in JavaScript:
- Chapter 6: Arrays in JavaScript
- 1. Creating Arrays
- 2. Accessing Array Elements
- 3. Modifying Arrays
- 4. Array Properties and Methods
- 5. Looping Through Arrays
- 6. Array Methods
- 7. Multidimensional Arrays
- 8. Array Destructuring
- Most Used Array Methods:
- Chapter 7: Strings in JavaScript
- 1. Creating Strings
- 2. String Properties
- 3. Accessing Characters in a String
- 4. String Methods
- 5. String Concatenation
- 6. Template Literals
- 7. Escape Characters
- 8. String Immutability
- 9. Comparing Strings
- 10. Trim Method
- Most used String Methods:
- 1. length
- 2. charAt()
- 3. charCodeAt()
- 4. concat()
- 5. includes()
- 6. endsWith()
- 7. startsWith()
- 8. indexOf()
- 9. lastIndexOf()
- 10. slice()
- 11. substring()
- 12. substr()
- 13. toLowerCase()
- 14. toUpperCase()
- 15. trim()
- 16. trimStart() / trimLeft()
- 17. trimEnd() / trimRight()
- 18. replace()
- 19. replaceAll()
- 20. split()
- 21. padStart()
- 22. padEnd()
- 23. repeat()
- 24. match()
- 25. matchAll()
- 26. search()
- 27. toString()
- 28. valueOf()
- Summary of Strings in JavaScript:
- Chapter 8: ES6 Features (Modern JavaScript)
- The this Keyword in JavaScript
- 1. Global Context (Outside of any Function)
- 2. Inside a Regular Function
- 3. Inside an Object Method
- 4. Constructor Functions and Classes
- 5. this in Arrow Functions
- 6. this in Event Handlers
- 7. Explicitly Setting this with call(), apply(), and bind()
- 8. this in DOM Manipulation
- Summary of this Keyword Behavior
- Chapter8: Asynchronous JavaScript
- Chapter 9: JavaScript and the Browser
- Chapter 10: JavaScript Engines and Runtime
Great! Let's start with Chapter 1: Introduction to JavaScript.
Chapter 1: Introduction to JavaScript
What is JavaScript?
JavaScript is a high-level, dynamic programming language that is primarily used for creating interactive features on websites. It enables developers to manipulate web content, respond to user actions, and create dynamic elements on webpages.
JavaScript runs on the client-side (in the browser) and is known as the language of the web.
Role of JavaScript in Web Development
JavaScript is essential for adding interactivity to a website. It works alongside HTML (which structures the content) and CSS (which styles the content).
With JavaScript, you can:
Create dynamic content (e.g., showing/hiding elements, real-time updates)
Handle user inputs and events (e.g., form submissions, button clicks)
Make HTTP requests to servers (using AJAX, Fetch API)
Modify the Document Object Model (DOM), which represents the structure of a webpage.
How JavaScript Works in Browsers
Browsers have a built-in JavaScript engine (e.g., Chrome uses V8, Firefox uses SpiderMonkey) that interprets and executes JavaScript code.
JavaScript code can run directly in the browser without the need for any compilation (like other languages such as Java or C++).
Adding JavaScript to HTML
There are several ways to include JavaScript in an HTML document:
Inline JavaScript
This places JavaScript directly in the HTML tags.<button onclick="alert('Button Clicked!')">Click Me</button>
- The
onclick
event calls the JavaScript functionalert()
, which displays a message when the button is clicked.
- The
Internal JavaScript You can place JavaScript within the
<script>
tag inside the HTML file, typically in the<head>
or at the end of the<body>
tag.<!DOCTYPE html> <html> <head> <script> function showMessage() { alert("Hello, World!"); } </script> </head> <body> <button onclick="showMessage()">Show Message</button> </body> </html>
- The JavaScript is written inside the
<script>
tag and can be referenced by the HTML elements.
- The JavaScript is written inside the
External JavaScript For better separation of concerns, JavaScript can be placed in an external file (with a
.js
extension) and linked to the HTML document using the<script>
tag.<!-- HTML file (index.html) --> <html> <head> <script src="script.js"></script> <!-- External JS file --> </head> <body> <button onclick="showMessage()">Show Message</button> </body> </html>
// External JS file (script.js) function showMessage() { alert("Hello from External JavaScript!"); }
- This keeps your HTML and JavaScript code separate, which is cleaner and easier to maintain.
Basic Syntax in JavaScript
Case Sensitivity: JavaScript is case-sensitive, meaning
variable
andVariable
are different.Comments: You can add comments to explain the code:
Single-line comment:
// This is a comment
Multi-line comment:
/* This is a multi-line comment */
Statements: JavaScript code is written in statements, usually ending with a semicolon
;
.var name = "John"; console.log(name);
Whitespace: JavaScript ignores extra spaces and line breaks, so you can structure your code in a readable way without affecting its behavior.
That's the introduction to JavaScript! In the next chapter, we'll dive into the basics of JavaScript, such as variables, data types, operators, and functions.
Chapter 2: JavaScript Basics
1. Variables
Variables are used to store data that can be used and manipulated throughout your JavaScript code.
Variable Declaration
In modern JavaScript (ES6 and beyond), there are three ways to declare variables:
var
(older way, now rarely used):var
has function scope or global scope, and it is subject to hoisting.It can be re-declared and updated.
var name = "John";
var age = 25;
let
(modern and recommended):let
has block scope (limited to the nearest{}
block).It can be updated but cannot be re-declared within the same scope.
let city = "New York";
city = "Los Angeles"; // Valid
const
(for constants):const
also has block scope.It cannot be updated or re-declared once assigned.
const pi = 3.14159;
// pi = 3.14; // Error: Assignment to constant variable
2. Data Types
JavaScript has different data types for storing various types of data. The two main categories are primitive data types and reference data types.
Primitive Data Types
Number: Represents numeric values (both integers and floats).
let age = 30; // Integer let salary = 5000.5; // Float
String: Represents text enclosed in quotes (
""
,''
, or backticks``
).let name = "Alice"; let greeting = 'Hello'; let message = `Hi, ${name}!`; // Template literals
Boolean: Represents
true
orfalse
.let isOnline = true; let hasDiscount = false;
Undefined: A variable that has been declared but not assigned a value.
let score; // Undefined by default
Null: Represents an intentional absence of any value.
let data = null; // Explicitly set to null
Symbol: A unique and immutable value (often used for object property keys).
let uniqueID = Symbol('id');
BigInt: Used for integers larger than
Number.MAX_SAFE_INTEGER
.let largeNumber = BigInt(9007199254740991);
Reference Data Types
Object: Represents a collection of key-value pairs (used for more complex data structures).
let user = { name: "John", age: 30, isAdmin: false };
Array: Represents a list of values.
let numbers = [1, 2, 3, 4, 5];
3. Operators
Arithmetic Operators
Used for performing arithmetic calculations:
+
: Addition-
: Subtraction*
: Multiplication/
: Division%
: Modulus (remainder)**
: Exponentiation
let x = 10;
let y = 5;
console.log(x + y); // 15
console.log(x - y); // 5
console.log(x * y); // 50
console.log(x / y); // 2
console.log(x % y); // 0
console.log(x ** y); // 100000
Comparison Operators
Used to compare values:
==
: Equal to (checks for value equality, loose comparison)===
: Strict equal to (checks for value and type equality)!=
: Not equal to!==
: Strict not equal to>
: Greater than<
: Less than>=
: Greater than or equal to<=
: Less than or equal to
console.log(5 == '5'); // true (loose comparison)
console.log(5 === '5'); // false (strict comparison)
console.log(10 > 5); // true
Logical Operators
Used to combine or manipulate boolean values:
&&
: Logical AND (both conditions must be true)||
: Logical OR (one or both conditions must be true)!
: Logical NOT (negates a condition)
let a = true;
let b = false;
console.log(a && b); // false
console.log(a || b); // true
console.log(!a); // false
Assignment Operators
Used to assign values to variables:
=
: Assign+=
: Add and assign-=
: Subtract and assign*=
: Multiply and assign/=
: Divide and assign
let num = 10;
num += 5; // num = num + 5; => 15
4. Conditionals
if-else Statements
Used to execute code based on conditions:
let age = 20;
if (age >= 18) {
console.log("You are an adult.");
} else {
console.log("You are a minor.");
}
else if Statements
For multiple conditions:
let score = 75;
if (score >= 90) {
console.log("A grade");
} else if (score >= 75) {
console.log("B grade");
} else {
console.log("C grade");
}
switch Statements
For checking multiple values:
let day = 3;
switch(day) {
case 1:
console.log("Monday");
break;
case 2:
console.log("Tuesday");
break;
case 3:
console.log("Wednesday");
break;
default:
console.log("Invalid day");
}
5. Loops
for Loop
Executes code a specified number of times:
for (let i = 0; i < 5; i++) {
console.log(i); // 0 1 2 3 4
}
while Loop
Executes code while a condition is true:
let i = 0;
while (i < 5) {
console.log(i); // 0 1 2 3 4
i++;
}
do-while Loop
Executes the code block once before checking the condition:
let i = 0;
do {
console.log(i); // 0 1 2 3 4
i++;
} while (i < 5);
6. Functions
Functions are reusable blocks of code that perform a specific task.
Function Declaration
function greet() {
console.log("Hello!");
}
greet(); // Outputs: Hello!
Function with Parameters
function greet(name) {
console.log(`Hello, ${name}!`);
}
greet("Alice"); // Outputs: Hello, Alice!
Returning Values
function add(a, b) {
return a + b;
}
let sum = add(5, 10); // sum = 15
Anonymous Functions
Functions can also be defined without names and assigned to variables:
let greet = function(name) {
console.log(`Hello, ${name}!`);
};
greet("John");
Arrow Functions (ES6)
A concise way to write functions:
const multiply = (a, b) => a * b;
console.log(multiply(5, 3)); // Outputs: 15
That concludes Chapter 2: JavaScript Basics. We covered variables, data types, operators, conditionals, loops, and functions.
Chapter 3: Control Structures in JavaScript
In this chapter, we will explore advanced control structures that allow us to control the flow of code execution beyond basic if-else statements and loops.
1. Advanced Conditionals
Ternary Operator
The ternary operator is a shorthand for if-else
statements. It allows you to write conditionals in a single line.
let age = 18;
let canVote = (age >= 18) ? "Yes" : "No";
console.log(canVote); // Outputs: Yes
In the example above, the condition age >= 18
is checked. If true
, "Yes"
is returned; otherwise, "No"
is returned.
Nullish Coalescing Operator (??
)
This operator returns the right-hand side value when the left-hand side is null
or undefined
. It's useful for providing default values.
let username = null;
let defaultName = "Guest";
let displayName = username ?? defaultName;
console.log(displayName); // Outputs: Guest
If username
is null
, displayName
will be "Guest"
.
Optional Chaining (?.
)
This operator allows safe access to deeply nested properties without explicitly checking for null
or undefined
.
let user = {
name: "Alice",
address: { city: "New York" }
};
// Safe access to deeply nested properties
let city = user?.address?.city;
console.log(city); // Outputs: New York
let country = user?.address?.country;
console.log(country); // Outputs: undefined (safe access, no error)
2. Switch Statement
The switch
statement evaluates an expression and matches it against multiple cases. It can be useful for handling multiple conditions based on a single variable or expression.
let day = 3;
switch (day) {
case 1:
console.log("Monday");
break;
case 2:
console.log("Tuesday");
break;
case 3:
console.log("Wednesday");
break;
default:
console.log("Invalid day");
}
3. Loops with Control
break Statement
The break
statement is used to exit a loop early when a certain condition is met.
for (let i = 0; i < 5; i++) {
if (i === 3) {
break; // Exit the loop when i is 3
}
console.log(i); // Outputs: 0 1 2
}
continue Statement
The continue
statement skips the current iteration and moves to the next iteration of the loop.
for (let i = 0; i < 5; i++) {
if (i === 2) {
continue; // Skip the iteration when i is 2
}
console.log(i); // Outputs: 0 1 3 4
}
for...of Loop
This loop is used to iterate over iterable objects like arrays, strings, etc.
let fruits = ["Apple", "Banana", "Mango"];
for (let fruit of fruits) {
console.log(fruit);
}
// Outputs:
// Apple
// Banana
// Mango
for...in Loop
This loop is used to iterate over the keys (or properties) of an object.
let person = { name: "John", age: 30, city: "New York" };
for (let key in person) {
console.log(key + ": " + person[key]);
}
// Outputs:
// name: John
// age: 30
// city: New York
4. Error Handling (try-catch)
Error handling in JavaScript can be managed using the try-catch
block, which allows you to handle exceptions and errors without stopping the program's execution.
try-catch Block
try {
let result = 10 / 0; // Division by zero (though no error in JS)
console.log(result);
// Intentionally cause an error
let data = JSON.parse("invalid JSON");
} catch (error) {
console.log("An error occurred:", error.message);
}
The
try
block contains code that might throw an error.If an error occurs, control passes to the
catch
block, which handles the error.
finally Block
The finally
block is always executed after try-catch
, regardless of whether an error occurred or not.
try {
let data = JSON.parse("invalid JSON");
} catch (error) {
console.log("An error occurred:", error.message);
} finally {
console.log("This will always run.");
}
5. Throwing Custom Errors
You can throw custom errors using the throw
statement. This can be useful when you want to generate your own errors based on certain conditions.
function checkAge(age) {
if (age < 18) {
throw new Error("You must be at least 18 years old.");
}
console.log("Age is valid.");
}
try {
checkAge(16); // Throws an error
} catch (error) {
console.log(error.message); // Outputs: You must be at least 18 years old.
}
Summary of Control Structures in JavaScript:
Ternary Operator: Shorthand for
if-else
.Nullish Coalescing (
??
): Provides default values fornull
orundefined
.Optional Chaining (
?.
): Safely access nested object properties.Switch Statement: Used for checking multiple conditions.
Break & Continue: Control loop execution flow.
for...of: Iterate over iterable objects (arrays, strings).
for...in: Iterate over object keys.
try-catch-finally: Error handling with custom errors using
throw
.
That concludes Chapter 3.
Chapter 4: Functions in JavaScript
Functions are one of the most fundamental building blocks in JavaScript. In this chapter, we will explore how to define and use functions, as well as advanced topics like arrow functions, higher-order functions, and closures.
1. Defining Functions
A function is a block of reusable code that can be executed whenever needed.
Function Declaration
This is the most common way to define a function.
function greet() {
console.log("Hello, World!");
}
greet(); // Outputs: Hello, World!
Function with Parameters
You can pass values (arguments) to functions to perform operations on them.
function greet(name) {
console.log("Hello, " + name + "!");
}
greet("Alice"); // Outputs: Hello, Alice!
Function with Return Value
Functions can return values using the return
statement.
function add(a, b) {
return a + b;
}
let result = add(5, 3);
console.log(result); // Outputs: 8
2. Function Expressions
In JavaScript, functions can also be defined as expressions and assigned to variables.
const multiply = function (x, y) {
return x * y;
};
console.log(multiply(4, 5)); // Outputs: 20
Unlike function declarations, function expressions are not hoisted, meaning they must be defined before they are used.
3. Arrow Functions
Arrow functions provide a more concise syntax for writing functions. They are often used in modern JavaScript development.
const subtract = (a, b) => a - b;
console.log(subtract(10, 3)); // Outputs: 7
If there is only one parameter, you can omit the parentheses:
x => x + 1
.If the function body consists of only a single expression, you can omit the curly braces and
return
keyword.
Arrow Functions with Multiple Statements
const divide = (a, b) => {
if (b === 0) {
return "Cannot divide by zero";
}
return a / b;
};
console.log(divide(10, 2)); // Outputs: 5
4. Default Parameters
You can define default values for parameters in functions. If a value is not passed for a parameter, the default value will be used.
function greet(name = "Guest") {
console.log("Hello, " + name + "!");
}
greet(); // Outputs: Hello, Guest!
greet("Alice"); // Outputs: Hello, Alice!
5. Rest Parameters (...
)
Rest parameters allow you to pass an indefinite number of arguments as an array.
function sum(...numbers) {
return numbers.reduce((total, num) => total + num, 0);
}
console.log(sum(1, 2, 3, 4)); // Outputs: 10
The ...numbers
collects all arguments into an array.
6. Higher-Order Functions
Higher-order functions are functions that can take other functions as arguments or return functions as values. They are a key feature of functional programming in JavaScript.
Function as Argument
function greetPerson(person, callback) {
const message = `Hello, ${person}!`;
callback(message);
}
function printMessage(message) {
console.log(message);
}
greetPerson("Alice", printMessage); // Outputs: Hello, Alice!
Function Returning a Function
function createMultiplier(factor) {
return function (number) {
return number * factor;
};
}
const double = createMultiplier(2);
console.log(double(5)); // Outputs: 10
7. Closures
A closure is a function that remembers the variables from its outer scope even after the outer function has finished executing.
function outer() {
let count = 0;
return function inner() {
count++;
return count;
};
}
const increment = outer();
console.log(increment()); // Outputs: 1
console.log(increment()); // Outputs: 2
In this example, the inner
function retains access to the count
variable even after outer
has executed.
8. Immediately Invoked Function Expressions (IIFE)
An IIFE is a function that is executed as soon as it is defined. This is useful when you want to create a separate scope and avoid polluting the global namespace.
(function () {
console.log("This function runs immediately!");
})();
9. Function Scope
JavaScript functions have their own scope. Variables defined inside a function are not accessible from outside the function.
function sayHello() {
let message = "Hello, World!";
console.log(message); // Outputs: Hello, World!
}
sayHello();
console.log(message); // Error: message is not defined
Variables declared inside a function can only be accessed within that function.
Summary of Functions in JavaScript:
Function Declaration: A basic way to define reusable code blocks.
Function Expression: Functions as expressions, can be assigned to variables.
Arrow Functions: Concise syntax, especially for one-liners.
Default Parameters: Assign default values for function parameters.
Rest Parameters: Handle a variable number of arguments.
Higher-Order Functions: Functions that take or return other functions.
Closures: Functions that "remember" variables from their outer scope.
IIFE: Functions that are immediately executed upon definition.
Function Scope: Variables within functions are locally scoped.
Chapter 5: Objects in JavaScript
Objects are a fundamental concept in JavaScript, used to group related data and functionalities. They are collections of key-value pairs, where the key is a string (or symbol) and the value can be any type, including other objects or functions.
1. Creating Objects
There are multiple ways to create objects in JavaScript.
Object Literal Notation
This is the most common way to create an object.
const person = {
name: "John",
age: 30,
greet: function () {
console.log("Hello, " + this.name + "!");
},
};
console.log(person.name); // Outputs: John
person.greet(); // Outputs: Hello, John!
In this example, person
is an object with properties name
, age
, and a method greet
.
Using the new Object()
Syntax
You can also create objects using the Object()
constructor.
const car = new Object();
car.brand = "Toyota";
car.model = "Camry";
car.year = 2021;
console.log(car.brand); // Outputs: Toyota
This method is less common than object literal notation.
2. Accessing Object Properties
There are two ways to access object properties:
Dot Notation
console.log(person.name); // Outputs: John
Bracket Notation
Bracket notation allows you to use variable keys or keys with spaces.
console.log(person["name"]); // Outputs: John
const key = "age";
console.log(person[key]); // Outputs: 30
3. Adding and Modifying Properties
You can add or modify properties of an object after it's created.
person.job = "Engineer"; // Adding a new property
person.age = 31; // Modifying an existing property
console.log(person.job); // Outputs: Engineer
console.log(person.age); // Outputs: 31
4. Removing Properties
To delete a property from an object, use the delete
operator.
delete person.age;
console.log(person.age); // Outputs: undefined
5. Object Methods
Objects can have methods, which are functions defined as properties. Methods often use the this
keyword to refer to the object itself.
const dog = {
name: "Buddy",
bark: function () {
console.log(this.name + " says woof!");
},
};
dog.bark(); // Outputs: Buddy says woof!
In this case, this.name
refers to the name
property of the dog
object.
6. this
Keyword
The this
keyword refers to the object in which the function is called. It allows you to access the object's properties within its methods.
const user = {
name: "Alice",
greet: function () {
console.log("Hi, " + this.name + "!");
},
};
user.greet(); // Outputs: Hi, Alice!
If a function is called in a different context (e.g., detached from the object), the value of this
can change.
7. Nested Objects
Objects can contain other objects as properties, leading to a nested structure.
const company = {
name: "Tech Corp",
address: {
street: "123 Main St",
city: "New York",
},
};
console.log(company.address.city); // Outputs: New York
You can access properties of nested objects using dot notation.
8. Object Destructuring
Destructuring allows you to extract properties from an object into variables.
const { name, age } = person;
console.log(name); // Outputs: John
console.log(age); // Outputs: 31
Destructuring makes it easy to extract multiple properties from an object.
9. Checking for Properties
You can check whether an object has a certain property using the in
operator or the hasOwnProperty()
method.
console.log("name" in person); // Outputs: true
console.log(person.hasOwnProperty("age")); // Outputs: true
10. Iterating Over Object Properties
You can iterate over the properties of an object using for...in
.
for (let key in person) {
console.log(key + ": " + person[key]);
}
This will iterate over all enumerable properties of the object.
11. Object.assign()
Object.assign()
is used to copy the properties of one or more objects into a target object.
const target = { a: 1 };
const source = { b: 2, c: 3 };
const newObject = Object.assign(target, source);
console.log(newObject); // Outputs: { a: 1, b: 2, c: 3 }
12. Object.keys(), Object.values(), and Object.entries()
These methods allow you to get the keys, values, and key-value pairs from an object.
Object.keys()
returns an array of the object's keys.console.log(Object.keys(person)); // Outputs: ["name", "job", "greet"]
Object.values()
returns an array of the object's values.console.log(Object.values(person)); // Outputs: ["John", "Engineer", function]
Object.entries()
returns an array of key-value pairs.console.log(Object.entries(person)); // Outputs: [["name", "John"], ["job", "Engineer"], ["greet", function]]
Summary of Objects in JavaScript:
Objects are collections of key-value pairs used to store and manage data.
You can create objects using object literals or the
Object()
constructor.Object properties can be accessed, modified, and deleted using dot or bracket notation.
Objects can have methods, and the
this
keyword inside methods refers to the object itself.JavaScript supports nested objects, destructuring, and various built-in methods like
Object.keys()
andObject.assign()
to manipulate objects.
Chapter 6: Arrays in JavaScript
Arrays in JavaScript are used to store multiple values in a single variable. They are list-like objects that come with many built-in methods for working with ordered collections of data.
1. Creating Arrays
You can create arrays using square brackets []
or the Array
constructor.
// Using square brackets
const fruits = ["apple", "banana", "cherry"];
// Using the Array constructor
const numbers = new Array(1, 2, 3, 4);
2. Accessing Array Elements
Array elements are accessed using their index, starting from 0.
console.log(fruits[0]); // Outputs: apple
console.log(numbers[2]); // Outputs: 3
3. Modifying Arrays
You can modify arrays by assigning new values to specific indices or using array methods.
fruits[1] = "orange";
console.log(fruits); // Outputs: ["apple", "orange", "cherry"]
4. Array Properties and Methods
- Length Property: The
length
property gives the number of elements in the array.
console.log(fruits.length); // Outputs: 3
- Push and Pop:
push
adds an element to the end of the array, andpop
removes the last element.
fruits.push("grape");
console.log(fruits); // Outputs: ["apple", "orange", "cherry", "grape"]
fruits.pop();
console.log(fruits); // Outputs: ["apple", "orange", "cherry"]
- Shift and Unshift:
shift
removes the first element, andunshift
adds an element to the beginning of the array.
fruits.shift();
console.log(fruits); // Outputs: ["orange", "cherry"]
fruits.unshift("strawberry");
console.log(fruits); // Outputs: ["strawberry", "orange", "cherry"]
5. Looping Through Arrays
You can loop through arrays using for
, for...of
, or forEach
loops.
for (let i = 0; i < fruits.length; i++) {
console.log(fruits[i]);
}
for (let fruit of fruits) {
console.log(fruit);
}
fruits.forEach((fruit) => {
console.log(fruit);
});
6. Array Methods
JavaScript provides several methods for working with arrays:
map()
: Creates a new array by applying a function to each element.
const numbers = [1, 2, 3, 4];
const doubled = numbers.map(num => num * 2);
console.log(doubled); // Outputs: [2, 4, 6, 8]
filter()
: Creates a new array with elements that pass a condition.
const evenNumbers = numbers.filter(num => num % 2 === 0);
console.log(evenNumbers); // Outputs: [2, 4]
reduce()
: Reduces the array to a single value.
const sum = numbers.reduce((acc, curr) => acc + curr, 0);
console.log(sum); // Outputs: 10
find()
: Returns the first element that satisfies a condition.
const found = numbers.find(num => num > 2);
console.log(found); // Outputs: 3
some()
andevery()
: Checks if some or every element passes a condition.
console.log(numbers.some(num => num > 3)); // Outputs: true
console.log(numbers.every(num => num > 0)); // Outputs: true
sort()
: Sorts the elements of an array.
const fruits = ["banana", "apple", "cherry"];
fruits.sort();
console.log(fruits); // Outputs: ["apple", "banana", "cherry"]
concat()
: Combines two or more arrays.
const moreFruits = ["pear", "mango"];
const combined = fruits.concat(moreFruits);
console.log(combined); // Outputs: ["apple", "banana", "cherry", "pear", "mango"]
slice()
: Returns a portion of the array without modifying the original array.
const sliced = fruits.slice(1, 3);
console.log(sliced); // Outputs: ["banana", "cherry"]
splice()
: Adds or removes elements from an array.
fruits.splice(1, 1, "grape"); // Removes "banana" and adds "grape"
console.log(fruits); // Outputs: ["apple", "grape", "cherry"]
7. Multidimensional Arrays
Arrays can also contain other arrays (multidimensional arrays).
const matrix = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
];
console.log(matrix[1][2]); // Outputs: 6
8. Array Destructuring
You can use destructuring to extract values from arrays.
const [first, second, third] = fruits;
console.log(first, second, third); // Outputs: apple grape cherry
Most Used Array Methods:
JavaScript Array Methods with Examples
Arrays in JavaScript come with many built-in methods that allow us to perform operations such as adding, removing, and manipulating elements. Let’s go through each array method along with examples and detailed explanations.
1. push()
Adds one or more elements to the end of an array and returns the new length of the array.
Example:
let fruits = ['apple', 'banana'];
let newLength = fruits.push('orange', 'mango');
console.log(fruits); // Output: ['apple', 'banana', 'orange', 'mango']
console.log(newLength); // Output: 4
Explanation: We add 'orange' and 'mango' to the end of the fruits
array. The method returns the new length of the array (4).
2. pop()
Removes the last element from an array and returns that element.
Example:
let fruits = ['apple', 'banana', 'orange'];
let lastFruit = fruits.pop();
console.log(fruits); // Output: ['apple', 'banana']
console.log(lastFruit); // Output: 'orange'
Explanation: The pop()
method removes the last element ('orange') from the fruits
array and returns it.
3. shift()
Removes the first element from an array and returns that element. This method changes the length of the array.
Example:
let fruits = ['apple', 'banana', 'orange'];
let firstFruit = fruits.shift();
console.log(fruits); // Output: ['banana', 'orange']
console.log(firstFruit); // Output: 'apple'
Explanation: The first element ('apple') is removed from the array, and the array is updated.
4. unshift()
Adds one or more elements to the beginning of an array and returns the new length of the array.
Example:
let fruits = ['banana', 'orange'];
let newLength = fruits.unshift('apple', 'mango');
console.log(fruits); // Output: ['apple', 'mango', 'banana', 'orange']
console.log(newLength); // Output: 4
Explanation: We add 'apple' and 'mango' to the beginning of the array, and the new length of the array is returned.
5. concat()
Merges two or more arrays and returns a new array.
Example:
let arr1 = [1, 2];
let arr2 = [3, 4];
let mergedArray = arr1.concat(arr2);
console.log(mergedArray); // Output: [1, 2, 3, 4]
Explanation: The arrays arr1
and arr2
are merged into a new array [1, 2, 3, 4]
.
6. slice()
Returns a shallow copy of a portion of an array into a new array object. The slice begins at the specified start
index and ends before the specified end
index (non-inclusive).
Example:
let fruits = ['apple', 'banana', 'orange', 'mango'];
let slicedFruits = fruits.slice(1, 3);
console.log(slicedFruits); // Output: ['banana', 'orange']
Explanation: The slice()
method extracts elements from index 1 to index 3 (excluding index 3).
7. splice()
Changes the contents of an array by removing, replacing, or adding elements.
Example (Removing elements):
let fruits = ['apple', 'banana', 'orange', 'mango'];
let removedFruits = fruits.splice(1, 2);
console.log(fruits); // Output: ['apple', 'mango']
console.log(removedFruits); // Output: ['banana', 'orange']
Explanation: We remove 2 elements starting from index 1 ('banana', 'orange'). The original array is modified.
Example (Adding elements):
let fruits = ['apple', 'mango'];
fruits.splice(1, 0, 'banana', 'orange');
console.log(fruits); // Output: ['apple', 'banana', 'orange', 'mango']
Explanation: At index 1, we insert 'banana' and 'orange' without removing any elements.
8. forEach()
Executes a provided function once for each array element.
Example:
let numbers = [1, 2, 3];
numbers.forEach(function(num) {
console.log(num * 2);
});
// Output: 2, 4, 6
Explanation: The forEach()
method iterates over each element in the numbers
array, doubling it and logging the result.
9. map()
Creates a new array populated with the results of calling a provided function on every element in the calling array.
Example:
let numbers = [1, 2, 3];
let doubled = numbers.map(num => num * 2);
console.log(doubled); // Output: [2, 4, 6]
Explanation: The map()
method returns a new array where each element is the result of multiplying the original element by 2.
10. filter()
Creates a new array with all elements that pass the test implemented by the provided function.
Example:
let numbers = [1, 2, 3, 4, 5];
let evenNumbers = numbers.filter(num => num % 2 === 0);
console.log(evenNumbers); // Output: [2, 4]
Explanation: The filter()
method returns a new array containing only the even numbers.
11. reduce()
Executes a reducer function on each element of the array, resulting in a single output value.
Example:
let numbers = [1, 2, 3, 4];
let sum = numbers.reduce((acc, curr) => acc + curr, 0);
console.log(sum); // Output: 10
Explanation: The reduce()
method adds all elements of the numbers
array, starting with an initial value of 0.
12. find()
Returns the value of the first element in the array that satisfies the provided testing function.
Example:
let numbers = [5, 12, 8, 130, 44];
let found = numbers.find(num => num > 10);
console.log(found); // Output: 12
Explanation: The find()
method returns the first number in the array that is greater than 10.
13. findIndex()
Returns the index of the first element that satisfies the provided testing function. Otherwise, it returns -1
.
Example:
let numbers = [5, 12, 8, 130, 44];
let index = numbers.findIndex(num => num > 10);
console.log(index); // Output: 1
Explanation: The findIndex()
method returns the index of the first element greater than 10, which is at index 1.
14. every()
Tests whether all elements in the array pass the test implemented by the provided function. It returns a Boolean value.
Example:
let numbers = [2, 4, 6];
let allEven = numbers.every(num => num % 2 === 0);
console.log(allEven); // Output: true
Explanation: The every()
method checks if all elements in the array are even. Since all numbers are even, it returns true
.
15. some()
Tests whether at least one element in the array passes the test implemented by the provided function. It returns a Boolean value.
Example:
let numbers = [1, 2, 3, 4];
let hasEven = numbers.some(num => num % 2 === 0);
console.log(hasEven); // Output: true
Explanation: The some()
method checks if at least one element is even. Since 2 and 4 are even, it returns true
.
16. includes()
Determines whether an array includes a certain value among its entries, returning true
or false
.
Example:
let fruits = ['apple', 'banana', 'mango'];
console.log(fruits.includes('banana')); // Output: true
console.log(fruits.includes('grape')); // Output: false
Explanation: The includes()
method checks whether 'banana' exists in the array and returns true
.
17. sort()
Sorts the elements of an array in place and returns the sorted array.
Example:
let numbers = [3, 1, 4, 2];
numbers.sort();
console.log(numbers); // Output: [1, 2, 3, 4]
Explanation: The sort()
method sorts the array in ascending order.
Example with custom comparator:
let numbers = [10, 5, 20, 1];
numbers.sort((a, b) => a - b); console.log(numbers); // Output: [1, 5, 10, 20]
**Explanation**: Using a custom comparator function `(a, b) => a - b`, the array is sorted in numerical order.
---
### **18. `reverse()`**
Reverses the order of the elements in an array.
#### **Example:**
```js
let numbers = [1, 2, 3];
numbers.reverse();
console.log(numbers); // Output: [3, 2, 1]
Explanation: The reverse()
method reverses the order of the array elements.
19. join()
Joins all elements of an array into a string, separated by a specified separator.
Example:
let fruits = ['apple', 'banana', 'mango'];
let fruitString = fruits.join(', ');
console.log(fruitString); // Output: 'apple, banana, mango'
Explanation: The join()
method creates a string with the array elements separated by ,
.
20. flat()
Creates a new array with all sub-array elements concatenated into it recursively up to the specified depth.
Example:
let nestedArray = [1, [2, 3], [4, [5]]];
let flatArray = nestedArray.flat(2);
console.log(flatArray); // Output: [1, 2, 3, 4, 5]
Explanation: The flat()
method flattens the nested arrays up to a depth of 2.
These are some of the most commonly used array methods in JavaScript, each with its specific purpose and behavior!
Summary of Arrays in JavaScript:
Arrays are used to store multiple values in a single variable.
They come with many built-in methods for performing operations like adding, removing, and manipulating data.
Arrays can be looped through and destructured for efficient handling of data.
Advanced methods like
map
,reduce
,filter
, andsort
allow you to work with arrays in a functional way.
Chapter 7: Strings in JavaScript
Strings in JavaScript are used to represent textual data. They are a sequence of characters enclosed in single quotes ('
), double quotes ("
), or backticks (`
). JavaScript provides a wide range of methods and properties for working with strings.
1. Creating Strings
You can create strings using different types of quotes:
const singleQuoteStr = 'Hello, world!';
const doubleQuoteStr = "Hello, world!";
const templateLiteralStr = `Hello, world!`;
Single and Double Quotes: Strings created with single (
'
) or double ("
) quotes behave similarly.Template Literals: Strings created with backticks (
`
) allow for embedding expressions and multi-line strings.
2. String Properties
length
: Returns the length (number of characters) in a string.
const str = "JavaScript";
console.log(str.length); // Outputs: 10
3. Accessing Characters in a String
You can access individual characters in a string using bracket notation or the charAt()
method.
const str = "JavaScript";
console.log(str[0]); // Outputs: "J"
console.log(str.charAt(1)); // Outputs: "a"
4. String Methods
JavaScript provides many built-in methods for string manipulation:
toUpperCase()
andtoLowerCase()
: Converts the string to upper or lower case.
console.log(str.toUpperCase()); // Outputs: "JAVASCRIPT"
console.log(str.toLowerCase()); // Outputs: "javascript"
indexOf()
: Returns the index of the first occurrence of a substring. If not found, returns-1
.
console.log(str.indexOf("Script")); // Outputs: 4
console.log(str.indexOf("script")); // Outputs: -1
includes()
: Checks if a substring is present in the string, returningtrue
orfalse
.
console.log(str.includes("Java")); // Outputs: true
slice()
: Extracts a section of the string and returns it as a new string.
console.log(str.slice(0, 4)); // Outputs: "Java"
substring()
: Similar toslice()
, but does not accept negative indices.
console.log(str.substring(4, 10)); // Outputs: "Script"
replace()
: Replaces the first occurrence of a substring with another.
const newStr = str.replace("Java", "Type");
console.log(newStr); // Outputs: "TypeScript"
split()
: Splits a string into an array of substrings based on a specified delimiter.
const sentence = "This is JavaScript";
const words = sentence.split(" ");
console.log(words); // Outputs: ["This", "is", "JavaScript"]
5. String Concatenation
You can concatenate (combine) strings using the +
operator or template literals.
const greeting = "Hello, " + "world!";
console.log(greeting); // Outputs: "Hello, world!"
// Using template literals
const name = "John";
const message = `Hello, ${name}! Welcome to JavaScript.`;
console.log(message); // Outputs: "Hello, John! Welcome to JavaScript."
6. Template Literals
Template literals allow for embedding expressions inside strings using ${}
. They also support multi-line strings without the need for special characters.
const age = 25;
const introduction = `I am ${age} years old.`;
console.log(introduction); // Outputs: "I am 25 years old."
// Multi-line string
const multiLine = `This is
a multi-line
string.`;
console.log(multiLine);
7. Escape Characters
You can include special characters in a string using escape sequences. Some common escape characters:
\n
: Newline\t
: Tab\'
: Single quote\"
: Double quote\\
: Backslash
const text = 'He said, "It\'s a beautiful day."';
console.log(text); // Outputs: He said, "It's a beautiful day."
8. String Immutability
Strings in JavaScript are immutable, meaning they cannot be changed after creation. Any operation on a string, such as concatenation or replacement, creates a new string rather than modifying the original.
let str = "Hello";
str[0] = "h"; // This will not change the string
console.log(str); // Outputs: "Hello"
9. Comparing Strings
You can compare strings using relational operators like ==
, ===
, >
, <
, etc. String comparison is case-sensitive.
console.log("apple" > "banana"); // Outputs: false (alphabetical comparison)
console.log("Apple" === "apple"); // Outputs: false (case-sensitive)
10. Trim Method
trim()
: Removes whitespace from both ends of a string.
const str = " Hello, world! ";
console.log(str.trim()); // Outputs: "Hello, world!"
Most used String Methods:
Here’s a comprehensive list of commonly used JavaScript string methods with explanations and examples:
1. length
Returns the length of a string.
Example:
let str = "Hello";
console.log(str.length); // Output: 5
Explanation: length
returns the number of characters in the string.
2. charAt()
Returns the character at a specified index.
Example:
let str = "Hello";
console.log(str.charAt(1)); // Output: 'e'
Explanation: charAt(1)
returns the character at index 1, which is 'e'
.
3. charCodeAt()
Returns the Unicode value of the character at a specified index.
Example:
let str = "A";
console.log(str.charCodeAt(0)); // Output: 65
Explanation: charCodeAt(0)
returns the Unicode value of the character 'A'
, which is 65
.
4. concat()
Concatenates (joins) two or more strings.
Example:
let str1 = "Hello";
let str2 = "World";
console.log(str1.concat(" ", str2)); // Output: 'Hello World'
Explanation: concat()
joins two strings together.
5. includes()
Checks if a string contains a specified substring, returning true
or false
.
Example:
let str = "Hello World";
console.log(str.includes("World")); // Output: true
Explanation: includes()
checks if 'World'
exists in the string.
6. endsWith()
Checks if a string ends with a specified substring.
Example:
let str = "Hello World";
console.log(str.endsWith("World")); // Output: true
Explanation: endsWith()
checks if the string ends with 'World'
.
7. startsWith()
Checks if a string starts with a specified substring.
Example:
let str = "Hello World";
console.log(str.startsWith("Hello")); // Output: true
Explanation: startsWith()
checks if the string starts with 'Hello'
.
8. indexOf()
Returns the index of the first occurrence of a specified substring.
Example:
let str = "Hello World";
console.log(str.indexOf("o")); // Output: 4
Explanation: indexOf()
returns the index of the first occurrence of 'o'
, which is 4
.
9. lastIndexOf()
Returns the index of the last occurrence of a specified substring.
Example:
let str = "Hello World";
console.log(str.lastIndexOf("o")); // Output: 7
Explanation: lastIndexOf()
returns the last occurrence of 'o'
, which is at index 7
.
10. slice()
Extracts a part of a string and returns it as a new string.
Example:
let str = "Hello World";
console.log(str.slice(0, 5)); // Output: 'Hello'
Explanation: slice(0, 5)
extracts the substring from index 0 to index 5 (excluding 5).
11. substring()
Extracts characters between two specified indices.
Example:
let str = "Hello World";
console.log(str.substring(0, 5)); // Output: 'Hello'
Explanation: Similar to slice()
, substring(0, 5)
extracts characters from index 0 to 5.
12. substr()
Extracts a substring from a specified start index and length (deprecated).
Example:
let str = "Hello World";
console.log(str.substr(0, 5)); // Output: 'Hello'
Explanation: substr(0, 5)
extracts 5 characters starting from index 0.
13. toLowerCase()
Converts a string to lowercase.
Example:
let str = "Hello World";
console.log(str.toLowerCase()); // Output: 'hello world'
Explanation: toLowerCase()
converts all characters to lowercase.
14. toUpperCase()
Converts a string to uppercase.
Example:
let str = "Hello World";
console.log(str.toUpperCase()); // Output: 'HELLO WORLD'
Explanation: toUpperCase()
converts all characters to uppercase.
15. trim()
Removes whitespace from both sides of a string.
Example:
let str = " Hello World ";
console.log(str.trim()); // Output: 'Hello World'
Explanation: trim()
removes leading and trailing whitespace.
16. trimStart()
/ trimLeft()
Removes whitespace from the beginning of a string.
Example:
let str = " Hello World";
console.log(str.trimStart()); // Output: 'Hello World'
Explanation: trimStart()
removes whitespace from the beginning.
17. trimEnd()
/ trimRight()
Removes whitespace from the end of a string.
Example:
let str = "Hello World ";
console.log(str.trimEnd()); // Output: 'Hello World'
Explanation: trimEnd()
removes whitespace from the end.
18. replace()
Replaces a substring with a new value.
Example:
let str = "Hello World";
console.log(str.replace("World", "JavaScript")); // Output: 'Hello JavaScript'
Explanation: replace()
replaces the first occurrence of 'World'
with 'JavaScript'
.
19. replaceAll()
Replaces all occurrences of a substring with a new value.
Example:
let str = "apple apple";
console.log(str.replaceAll("apple", "banana")); // Output: 'banana banana'
Explanation: replaceAll()
replaces all instances of 'apple'
with 'banana'
.
20. split()
Splits a string into an array of substrings, based on a specified separator.
Example:
let str = "apple, banana, mango";
let fruits = str.split(", ");
console.log(fruits); // Output: ['apple', 'banana', 'mango']
Explanation: split(", ")
splits the string into an array of fruits.
21. padStart()
Pads the beginning of a string with another string until a given length is reached.
Example:
let str = "5";
console.log(str.padStart(3, "0")); // Output: '005'
Explanation: padStart(3, "0")
adds zeros to the start until the length is 3.
22. padEnd()
Pads the end of a string with another string until a given length is reached.
Example:
let str = "5";
console.log(str.padEnd(3, "0")); // Output: '500'
Explanation: padEnd(3, "0")
adds zeros to the end until the length is 3.
23. repeat()
Repeats a string a specified number of times.
Example:
let str = "Hello ";
console.log(str.repeat(3)); // Output: 'Hello Hello Hello '
Explanation: repeat(3)
repeats the string 'Hello '
three times.
24. match()
Matches a string against a regular expression and returns an array of results.
Example:
let str = "Hello 123";
let result = str.match(/\d+/);
console.log(result); // Output: ['123']
Explanation: match()
returns an array containing the digits in the string.
25. matchAll()
Returns an iterator for all matches against a regular expression.
Example:
let str = "apple banana apple";
let result = [...str.matchAll(/apple/g)];
console.log(result); // Output: [['apple'], ['apple']]
Explanation: matchAll()
finds all occurrences of 'apple'
.
26. search()
Searches for a match between a regular expression and the string and returns the index of the match.
Example:
let str = "Hello 123";
console.log(str.search(/\d+/)); // Output: 6
Explanation: search()
returns the index of the first number in the string.
27. toString()
Returns the string representation of an object (usually called on non-string objects).
Example:
let num = 123;
console.log(num.toString()); // Output: '123'
Explanation: toString()
converts the number 123
into a string '123'
.
28. valueOf()
Returns the primitive value of
a string object.
Example:
let str = new String("Hello");
console.log(str.valueOf()); // Output: 'Hello'
Explanation: valueOf()
returns the primitive string value.
These are the key methods for manipulating strings in JavaScript! Let me know if you'd like more details on any of them.
Summary of Strings in JavaScript:
Strings are used to represent and manipulate text.
JavaScript provides many built-in methods for string manipulation, such as
slice()
,replace()
, andsplit()
.Strings can be concatenated using the
+
operator or template literals.Template literals allow for embedding expressions and creating multi-line strings.
Strings are immutable, meaning that they cannot be changed after creation.
Chapter 8: ES6 Features (Modern JavaScript)
ECMAScript 6 (ES6), also known as ECMAScript 2015, introduced several new features and enhancements to JavaScript, making it more powerful, concise, and easier to work with. These features have since become standard in modern JavaScript development.
In this chapter, we will explore the most important ES6 features:
1. let
and const
Before ES6, variables in JavaScript were declared using var
. ES6 introduced two new keywords for declaring variables: let
and const
.
let
: Declares a block-scoped variable, which can be reassigned.
let age = 25;
age = 30; // Reassignment is allowed
const
: Declares a block-scoped constant that cannot be reassigned. Once assigned, its value cannot change.
const name = "John";
name = "Jane"; // Error: Assignment to constant variable
- Block Scope: Both
let
andconst
are block-scoped, meaning they only exist within the block{}
where they are declared.
if (true) {
let x = 10;
console.log(x); // Outputs: 10
}
console.log(x); // Error: x is not defined
2. Arrow Functions
Arrow functions provide a more concise syntax for writing functions and automatically bind this
to the surrounding context.
- Traditional Function:
const add = function (a, b) {
return a + b;
};
console.log(add(5, 10)); // Outputs: 15
- Arrow Function:
const add = (a, b) => a + b;
console.log(add(5, 10)); // Outputs: 15
Arrow functions can omit parentheses if they take a single parameter:
const greet = name => `Hello, ${name}!`;
console.log(greet("John")); // Outputs: "Hello, John!"
3. Template Literals
Template literals (introduced in the previous chapter) allow embedding expressions and multi-line strings.
const name = "John";
const greeting = `Hello, ${name}! Welcome to ES6.`;
console.log(greeting); // Outputs: "Hello, John! Welcome to ES6."
4. Destructuring
Destructuring allows you to unpack values from arrays or properties from objects into distinct variables.
- Array Destructuring:
const arr = [1, 2, 3];
const [first, second, third] = arr;
console.log(first, second, third); // Outputs: 1 2 3
- Object Destructuring:
const person = { name: "John", age: 25 };
const { name, age } = person;
console.log(name, age); // Outputs: John 25
5. Default Parameters
Default parameters allow you to set default values for function parameters if no argument is passed.
const greet = (name = "Guest") => `Hello, ${name}!`;
console.log(greet()); // Outputs: "Hello, Guest!"
console.log(greet("John")); // Outputs: "Hello, John!"
6. Rest and Spread Operators
- Rest Operator (
...
): Collects all remaining elements into an array.
const sum = (a, b, ...rest) => {
console.log(rest); // Outputs: [3, 4, 5]
return a + b;
};
sum(1, 2, 3, 4, 5); // Outputs: 3
- Spread Operator (
...
): Spreads elements of an array or object into individual elements.
const arr1 = [1, 2, 3];
const arr2 = [...arr1, 4, 5];
console.log(arr2); // Outputs: [1, 2, 3, 4, 5]
const obj1 = { name: "John" };
const obj2 = { ...obj1, age: 25 };
console.log(obj2); // Outputs: { name: "John", age: 25 }
7. Enhanced Object Literals
ES6 introduced shorthand notation for object properties and methods.
const name = "John";
const age = 25;
// Property shorthand
const person = { name, age };
console.log(person); // Outputs: { name: "John", age: 25 }
// Method shorthand
const user = {
sayHi() {
console.log("Hi!");
}
};
user.sayHi(); // Outputs: "Hi!"
8. Classes
ES6 introduced classes, which are syntactical sugar over JavaScript's existing prototype-based inheritance.
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
greet() {
console.log(`Hello, my name is ${this.name}.`);
}
}
const john = new Person("John", 25);
john.greet(); // Outputs: "Hello, my name is John."
9. Modules
ES6 introduced native support for modules, allowing you to export and import code between files.
- Exporting:
// module.js
export const greet = name => `Hello, ${name}!`;
- Importing:
// main.js
import { greet } from './module.js';
console.log(greet("John")); // Outputs: "Hello, John!"
10. Promises
Promises provide a cleaner way to handle asynchronous operations in JavaScript, avoiding "callback hell."
const myPromise = new Promise((resolve, reject) => {
const success = true;
if (success) {
resolve("Operation succeeded!");
} else {
reject("Operation failed.");
}
});
myPromise
.then(result => console.log(result)) // Outputs: "Operation succeeded!"
.catch(error => console.error(error)); // Handles rejection
11. Symbol
Symbol
is a primitive data type introduced in ES6. Symbols are unique and immutable, making them useful for creating unique object properties.
const id = Symbol("id");
const user = {
[id]: 123,
name: "John"
};
console.log(user[id]); // Outputs: 123
12. Iterators and Generators
- Iterators: Objects that provide a sequence of values, typically used with loops like
for...of
.
const iterable = [1, 2, 3];
const iterator = iterable[Symbol.iterator]();
console.log(iterator.next()); // Outputs: { value: 1, done: false }
console.log(iterator.next()); // Outputs: { value: 2, done: false }
console.log(iterator.next()); // Outputs: { value: 3, done: false }
- Generators: Functions that return iterators and can pause their execution with
yield
.
function* myGenerator() {
yield 1;
yield 2;
yield 3;
}
const gen = myGenerator();
console.log(gen.next().value); // Outputs: 1
console.log(gen.next().value); // Outputs: 2
console.log(gen.next().value); // Outputs: 3
Summary of ES6 Features
let
andconst
provide block-scoped variable declarations.Arrow functions offer a concise syntax and automatic binding of
this
.Template literals allow embedding expressions and creating multi-line strings.
Destructuring simplifies extracting values from arrays and objects.
Default parameters, rest, and spread operators make function and array/object manipulation more powerful.
Classes provide a new syntax for working with object-oriented code.
Modules enable exporting and importing code between files.
Promises improve handling of asynchronous operations.
Symbols create unique object keys.
Iterators and generators provide powerful tools for working with sequences.
The this
Keyword in JavaScript
The this
keyword is one of the most important and sometimes confusing concepts in JavaScript. It refers to the context in which a function is invoked. The value of this
depends on where and how the function is called, not where it is defined.
Let’s explore the various contexts in which this
behaves differently.
1. Global Context (Outside of any Function)
In the global execution context, this
refers to the global object:
In browsers, the global object is
window
.In Node.js, it's the
global
object.
console.log(this); // In browsers, this will output the window object
2. Inside a Regular Function
In non-strict mode, when this
is used inside a function, it refers to the global object (window in the browser).
function show() {
console.log(this); // Outputs: window (global object in browser)
}
show();
In strict mode, this
in a regular function is undefined
.
"use strict";
function show() {
console.log(this); // Outputs: undefined
}
show();
3. Inside an Object Method
When a function is invoked as a method of an object, this
refers to the object to which the method belongs.
const person = {
name: "John",
greet: function () {
console.log(this.name); // 'this' refers to the 'person' object
}
};
person.greet(); // Outputs: "John"
4. Constructor Functions and Classes
When using constructor functions or classes, this
refers to the newly created instance of the object.
- Constructor Function:
function Person(name) {
this.name = name;
}
const john = new Person("John");
console.log(john.name); // Outputs: "John"
- Class Syntax:
class Person {
constructor(name) {
this.name = name;
}
greet() {
console.log(`Hello, my name is ${this.name}`);
}
}
const john = new Person("John");
john.greet(); // Outputs: "Hello, my name is John"
5. this
in Arrow Functions
Arrow functions behave differently with this
. Unlike regular functions, arrow functions do not have their own this
context. Instead, they inherit this
from the surrounding lexical scope (i.e., where the arrow function is defined).
const person = {
name: "John",
greet: function () {
const inner = () => {
console.log(this.name); // Arrow function inherits 'this' from the outer method
};
inner();
}
};
person.greet(); // Outputs: "John"
6. this
in Event Handlers
In event handlers, this
refers to the element that fired the event.
const button = document.querySelector("button");
button.addEventListener("click", function () {
console.log(this); // 'this' refers to the button element
});
If you use an arrow function in an event handler, this
will not refer to the element, as arrow functions inherit this
from the enclosing context.
button.addEventListener("click", () => {
console.log(this); // 'this' refers to the global object or undefined in strict mode
});
7. Explicitly Setting this
with call()
, apply()
, and bind()
JavaScript provides methods to explicitly set the value of this
in function calls:
call()
: Immediately invokes the function with a specifiedthis
value.apply()
: Similar tocall()
, but arguments are passed as an array.bind()
: Returns a new function with the specifiedthis
value, which can be called later.
function showName() {
console.log(this.name);
}
const person1 = { name: "John" };
const person2 = { name: "Jane" };
showName.call(person1); // Outputs: "John"
showName.apply(person2); // Outputs: "Jane"
const boundShowName = showName.bind(person1);
boundShowName(); // Outputs: "John"
8. this
in DOM Manipulation
When interacting with the DOM, this
refers to the HTML element in context:
<button onclick="sayHello()">Click me</button>
<script>
function sayHello() {
console.log(this); // 'this' refers to the button element
}
</script>
However, using arrow functions in DOM events leads to different behavior, as this
refers to the surrounding lexical scope:
<button id="btn">Click me</button>
<script>
document.getElementById("btn").addEventListener("click", () => {
console.log(this); // 'this' refers to the global object
});
</script>
Summary of this
Keyword Behavior
Global Scope:
this
refers to the global object (window/global).Regular Functions: In non-strict mode,
this
refers to the global object; in strict mode, it'sundefined
.Methods: Inside object methods,
this
refers to the object itself.Constructors/Classes:
this
refers to the new instance of the object created.Arrow Functions:
this
is lexically bound, meaning it inherits from the enclosing context.Event Handlers:
this
refers to the element that triggered the event.Explicit
this
Binding: Methods likecall()
,apply()
, andbind()
can explicitly set the value ofthis
.
Understanding how this
behaves in different contexts is crucial for mastering JavaScript, especially in larger codebases and frameworks like React.
Chapter8: Asynchronous JavaScript
Asynchronous JavaScript is crucial for managing tasks that take time to complete without blocking the main thread. This allows the browser or application to remain responsive while waiting for tasks like API calls, file reading, or animations to finish.
Asynchronous behavior in JavaScript can be handled using several mechanisms, including callbacks, promises, and async
/await
. Let’s explore them.
1. Synchronous vs Asynchronous Execution
In JavaScript, by default, code is executed line by line, i.e., synchronously. However, certain tasks like fetching data from a server or reading a file can take some time to complete, and during that period, we don't want the rest of the program to wait. Asynchronous JavaScript allows other tasks to be executed while waiting for long-running tasks to complete.
Synchronous Example:
console.log('Start');
console.log('Middle');
console.log('End');
// Output:
// Start
// Middle
// End
Asynchronous Example:
console.log('Start');
setTimeout(() => {
console.log('This is async');
}, 2000);
console.log('End');
// Output:
// Start
// End
// This is async (after 2 seconds)
2. Callbacks
A callback is a function passed into another function as an argument. The callback is invoked after a task is completed, enabling asynchronous behavior.
function fetchData(callback) {
setTimeout(() => {
console.log('Data fetched');
callback();
}, 2000);
}
function processData() {
console.log('Processing data...');
}
fetchData(processData); // Outputs: "Data fetched" then "Processing data..."
While callbacks work for asynchronous tasks, they can lead to callback hell if there are multiple nested callbacks:
function first(callback) {
setTimeout(() => {
console.log('First');
callback();
}, 1000);
}
function second(callback) {
setTimeout(() => {
console.log('Second');
callback();
}, 1000);
}
function third(callback) {
setTimeout(() => {
console.log('Third');
callback();
}, 1000);
}
first(() => {
second(() => {
third(() => {
console.log('All done');
});
});
});
3. Promises
Promises provide a cleaner way to handle asynchronous operations and avoid callback hell. A Promise represents a value that may be available now, in the future, or never. It can be in one of three states:
Pending: The initial state, neither fulfilled nor rejected.
Fulfilled: The operation was successful, and the promise has a result.
Rejected: The operation failed, and the promise has a reason for the failure.
Basic Promise Syntax:
const myPromise = new Promise((resolve, reject) => {
// Do something asynchronous
setTimeout(() => {
let success = true;
if (success) {
resolve('Operation successful');
} else {
reject('Operation failed');
}
}, 2000);
});
myPromise
.then((message) => {
console.log(message); // Outputs: "Operation successful"
})
.catch((error) => {
console.error(error); // Handles the error if rejected
});
resolve(value)
: Marks the promise as fulfilled and passesvalue
to the next.then()
block.reject(reason)
: Marks the promise as rejected and passesreason
to the.catch()
block.
4. Chaining Promises
Promises can be chained to handle multiple asynchronous operations in sequence.
const promise1 = new Promise((resolve) => {
setTimeout(() => resolve('First step'), 1000);
});
promise1
.then((result) => {
console.log(result); // "First step"
return 'Second step';
})
.then((result) => {
console.log(result); // "Second step"
return 'Third step';
})
.then((result) => {
console.log(result); // "Third step"
})
.catch((error) => {
console.error('Error:', error);
});
5. Promise.all()
and Promise.race()
Promise.all()
:
Runs multiple promises in parallel and waits for all of them to complete. If any promise fails, Promise.all()
fails.
const promiseA = Promise.resolve('A');
const promiseB = new Promise((resolve) => setTimeout(() => resolve('B'), 1000));
const promiseC = Promise.resolve('C');
Promise.all([promiseA, promiseB, promiseC])
.then((results) => {
console.log(results); // ["A", "B", "C"]
})
.catch((error) => {
console.error('Error:', error);
});
Promise.race()
:
Returns the result of the first promise to complete, whether fulfilled or rejected.
const promiseX = new Promise((resolve) => setTimeout(() => resolve('X'), 500));
const promiseY = new Promise((resolve) => setTimeout(() => resolve('Y'), 1000));
Promise.race([promiseX, promiseY])
.then((result) => {
console.log(result); // "X" (as it resolves faster)
});
6. async
and await
The async
and await
keywords were introduced to simplify working with promises and asynchronous code. An async
function returns a promise, and await
pauses the function execution until the promise is resolved or rejected.
Basic Syntax:
async function fetchData() {
const response = await new Promise((resolve) => {
setTimeout(() => resolve('Data fetched'), 2000);
});
console.log(response); // Outputs: "Data fetched"
}
fetchData();
You can use try...catch
for error handling:
async function fetchDataWithErrorHandling() {
try {
const response = await new Promise((_, reject) => {
setTimeout(() => reject('Error fetching data'), 2000);
});
console.log(response);
} catch (error) {
console.error(error); // Outputs: "Error fetching data"
}
}
fetchDataWithErrorHandling();
7. Example: Fetch API with Async/Await
A common use of asynchronous JavaScript is to make HTTP requests using the Fetch API. Here’s how to use async/await
with fetch()
:
async function getUserData() {
try {
const response = await fetch('https://jsonplaceholder.typicode.com/users');
const users = await response.json();
console.log(users); // Outputs fetched user data
} catch (error) {
console.error('Error fetching users:', error);
}
}
getUserData();
Summary
Asynchronous JavaScript is essential for tasks like HTTP requests, timers, and file handling.
Callbacks: Simple but can lead to callback hell.
Promises: Provide a cleaner way to manage asynchronous code and allow for chaining.
async
/await
: A more readable and modern way to work with promises.Methods like
Promise.all()
andPromise.race()
help manage multiple promises efficiently.
Chapter 9: JavaScript and the Browser
JavaScript's interaction with the browser is what makes it such a powerful language for building web applications. When a JavaScript file runs in a browser, it gains access to various browser-specific APIs that enable it to interact with web pages, handle user events, manipulate the DOM (Document Object Model), and more.
In this chapter, we’ll cover how JavaScript interacts with the browser, including the DOM, events, storage mechanisms, and other browser-specific features.
1. The DOM (Document Object Model)
The Document Object Model (DOM) represents the structure of an HTML document as a tree of nodes (elements). JavaScript can manipulate the DOM to dynamically change the content, structure, and style of a web page.
Basic DOM Example:
HTML structure:
<!DOCTYPE html>
<html>
<head>
<title>DOM Example</title>
</head>
<body>
<h1 id="main-heading">Hello, World!</h1>
<p class="message">Welcome to the DOM world.</p>
</body>
</html>
You can manipulate the DOM using JavaScript:
// Select the element with id="main-heading" and change its text content
document.getElementById('main-heading').textContent = 'Welcome to JavaScript!';
// Select all elements with the class "message" and change their style
document.querySelector('.message').style.color = 'blue';
Common DOM Methods:
document.getElementById(id)
: Selects an element by its ID.document.querySelector(selector)
: Selects the first element that matches a CSS selector.document.querySelectorAll(selector)
: Selects all elements that match a CSS selector.element.textContent
: Sets or gets the text content of an element.element.innerHTML
: Sets or gets the HTML content of an element.element.style
: Accesses or modifies inline CSS styles of an element.
2. DOM Manipulation
You can dynamically create, modify, or remove elements from the DOM using JavaScript.
Creating and Appending Elements:
// Create a new element
const newParagraph = document.createElement('p');
// Set its text content
newParagraph.textContent = 'This is a new paragraph created by JavaScript.';
// Append it to the body of the document
document.body.appendChild(newParagraph);
Removing Elements:
const elementToRemove = document.getElementById('main-heading');
elementToRemove.remove(); // Removes the element from the DOM
Modifying Attributes:
You can get or set attributes like src
, href
, class
, id
, etc., of DOM elements.
const link = document.querySelector('a');
link.setAttribute('href', 'https://www.example.com'); // Set href attribute
link.getAttribute('href'); // Get href attribute
link.removeAttribute('href'); // Remove href attribute
3. Events in JavaScript
Events in JavaScript represent user interactions or other actions that occur on a web page. Examples include clicks, key presses, and form submissions.
Event Listeners:
You can add event listeners to DOM elements to execute code when a specific event occurs.
const button = document.querySelector('button');
// Add a click event listener
button.addEventListener('click', function () {
alert('Button was clicked!');
});
Common Event Types:
click
: Fired when an element is clicked.mouseover
: Fired when the mouse is over an element.keydown
: Fired when a key is pressed on the keyboard.submit
: Fired when a form is submitted.load
: Fired when a page or image finishes loading.
4. Event Delegation
Instead of attaching event listeners to multiple child elements, you can use event delegation. This involves attaching a single event listener to a parent element and using event bubbling to handle events on child elements.
const list = document.querySelector('ul');
// Use event delegation by attaching the event listener to the parent element (ul)
list.addEventListener('click', function (event) {
if (event.target.tagName === 'LI') {
console.log('List item clicked:', event.target.textContent);
}
});
5. Browser Storage
JavaScript provides mechanisms for storing data in the browser, allowing web applications to save user preferences or cache data.
Local Storage:
Local storage allows you to store key-value pairs in the browser, and this data persists even after the browser is closed.
// Store data
localStorage.setItem('name', 'Purna');
// Retrieve data
const name = localStorage.getItem('name');
console.log(name); // Output: Purna
// Remove data
localStorage.removeItem('name');
// Clear all data
localStorage.clear();
Session Storage:
Similar to local storage, but the data is only available for the duration of the page session (until the browser or tab is closed).
sessionStorage.setItem('sessionName', 'Temporary Session');
console.log(sessionStorage.getItem('sessionName')); // Output: Temporary Session
6. Cookies
Cookies allow storing small amounts of data in the browser, often used for tracking sessions and user authentication.
// Set a cookie
document.cookie = 'username=Purna; expires=Thu, 18 Dec 2025 12:00:00 UTC; path=/';
// Get cookies
console.log(document.cookie); // Outputs all cookies in the document
7. The Window Object
The window
object represents the browser's window and is the global object for all JavaScript running in the browser. It includes properties and methods for controlling the browser window and interacting with the user.
Common Window Methods:
window.alert(message)
: Displays an alert box with a message.window.prompt(message)
: Displays a dialog box asking for user input.window.confirm(message)
: Displays a confirmation dialog with OK and Cancel buttons.window.location
: Represents the current URL and can be used to redirect or reload the page.
window.alert('Hello, world!');
window.location.href = 'https://www.example.com'; // Redirects the browser to a new URL
8. The document
Object
The document
object represents the web page loaded in the browser. It provides methods to access and manipulate the content and structure of the page.
Common Document Methods:
document.title
: Sets or gets the title of the document.document.body
: Refers to the<body>
element of the document.document.createElement(tagName)
: Creates a new HTML element.document.write(content)
: Writes directly to the document (rarely used).
document.title = 'New Title';
console.log(document.body); // Outputs the body element
9. Timers
JavaScript provides functions to execute code after a delay or repeatedly at a given interval.
setTimeout()
:
Executes a function once after a specified delay.
setTimeout(() => {
console.log('This runs after 2 seconds');
}, 2000); // 2 seconds = 2000 milliseconds
setInterval()
:
Executes a function repeatedly at a given interval.
const intervalId = setInterval(() => {
console.log('This runs every 2 seconds');
}, 2000);
// To stop the interval, use clearInterval
clearInterval(intervalId);
10. AJAX and Fetch API
AJAX (Asynchronous JavaScript and XML) allows you to send HTTP requests and receive responses without refreshing the page. The Fetch API is a modern, promise-based way to make HTTP requests.
fetch('https://jsonplaceholder.typicode.com/posts')
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('Error:', error));
Summary
In this chapter, we explored how JavaScript interacts with the browser:
The DOM allows you to manipulate the structure and content of the web page.
Events help handle user interactions like clicks and key presses.
Browser storage mechanisms like local storage and session storage allow you to save data.
Cookies are useful for tracking sessions and storing small pieces of data.
The
window
anddocument
objects give access to various browser-specific properties and methods.
Chapter 10: JavaScript Engines and Runtime
JavaScript engines and runtimes are fundamental to how JavaScript code is executed. JavaScript is not a compiled language; instead, it is interpreted or just-in-time compiled by JavaScript engines. Understanding how JavaScript engines and runtime environments work is essential for grasping how JavaScript interacts with different platforms, such as browsers or Node.js.
In this chapter, we’ll explore what a JavaScript engine is, how the runtime environment works, and what happens behind the scenes when you run JavaScript code.
1. What is a JavaScript Engine?
A JavaScript engine is a program or an interpreter that reads and executes JavaScript code. Every modern browser has its own JavaScript engine to run JavaScript code.
Popular JavaScript Engines:
V8: Developed by Google, V8 is used in Google Chrome and Node.js.
SpiderMonkey: Developed by Mozilla, SpiderMonkey is used in Firefox.
JavaScriptCore (Nitro): Developed by Apple, used in Safari.
Chakra: Developed by Microsoft, used in the old versions of Edge (before it switched to Chromium).
The primary job of a JavaScript engine is to:
Parse JavaScript code.
Compile it to machine code (using techniques like Just-in-Time compilation).
Execute the machine code.
How the V8 Engine Works:
The V8 engine compiles JavaScript to native machine code using a Just-in-Time (JIT) compiler. Here’s a simplified view of how the V8 engine works:
Parsing: The JavaScript source code is parsed into an Abstract Syntax Tree (AST).
Interpreter: V8 uses an interpreter called "Ignition" to execute the AST.
Compilation: Frequently executed code is compiled to highly optimized machine code using a JIT compiler called "TurboFan."
Garbage Collection: V8 uses a garbage collector to reclaim memory no longer in use by objects that are no longer needed.
2. JavaScript Runtime Environment
The JavaScript runtime environment provides everything necessary for a JavaScript program to execute. It includes not only the JavaScript engine but also APIs, libraries, and runtime-specific features that allow JavaScript to interact with the surrounding environment (e.g., browser, server).
Key Components of the Runtime Environment:
JavaScript Engine: Executes JavaScript code (e.g., V8 engine).
Call Stack: Manages the function execution order.
Heap: A memory storage space for dynamically allocated memory (e.g., objects, arrays).
Web APIs (in browsers): Provide APIs for interacting with browser-specific features like DOM, Fetch, and timers.
Event Loop: Manages asynchronous callbacks and ensures that functions are executed in order.
Callback Queue: A queue where asynchronous callbacks (like
setTimeout
) are stored before being executed.
3. The Call Stack
The call stack is a mechanism that tracks the function calls in a JavaScript program. When a function is called, it is added to the stack, and when it finishes, it is removed from the stack.
Example:
function first() {
console.log('First function');
}
function second() {
first();
console.log('Second function');
}
second();
Call Stack Process:
second()
is added to the call stack.Inside
second()
,first()
is called, sofirst()
is added to the stack.first()
finishes, so it is removed from the stack.second()
finishes and is removed from the stack.
4. The Event Loop and Asynchronous Execution
JavaScript is single-threaded, meaning it can only execute one piece of code at a time. However, it handles asynchronous tasks using the event loop, allowing the execution of callbacks after the synchronous code is complete.
Event Loop:
The event loop continuously checks if the call stack is empty. If the stack is empty, it processes tasks from the callback queue (e.g.,
setTimeout
callbacks, promises).Web APIs (in browsers) or Node.js APIs handle asynchronous tasks like HTTP requests, timers, or I/O operations. Once these tasks are completed, the results (callbacks) are added to the callback queue, and the event loop pushes them to the call stack when it's free.
Example:
console.log('Start');
setTimeout(() => {
console.log('This runs later');
}, 2000);
console.log('End');
Output:
Start
End
This runs later
Explanation: The synchronous code (console.log('Start')
and console.log('End')
) is executed first. The setTimeout
callback is added to the callback queue and executed later by the event loop.
5. JavaScript in the Browser
In a browser environment, JavaScript has access to browser-specific features through the Web APIs. These APIs are not part of the JavaScript language itself, but they are provided by the browser runtime to allow JavaScript to interact with the web page, make network requests, or handle user input.
Key Web APIs:
DOM (Document Object Model): Manipulate HTML content and structure.
Fetch API: Make network requests (e.g., fetch data from an API).
Timers:
setTimeout
andsetInterval
allow you to schedule code execution.LocalStorage/SessionStorage: Store data in the browser.
Example of Fetch API in the browser:
fetch('https://api.example.com/data')
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('Error:', error));
6. JavaScript in Node.js
Node.js is a server-side JavaScript runtime built on the V8 engine. It provides access to server-side features like the file system, networking, and child processes.
Key Node.js Features:
Modules: Organize code into reusable files (
require
andimport/export
).File System: Read/write files on the server.
HTTP: Handle incoming HTTP requests and send responses.
Example in Node.js:
const fs = require('fs');
fs.readFile('example.txt', 'utf8', (err, data) => {
if (err) {
console.error('Error reading file:', err);
} else {
console.log('File content:', data);
}
});
7. Just-in-Time Compilation (JIT)
JavaScript engines like V8 use Just-in-Time (JIT) compilation to optimize performance. Instead of interpreting JavaScript code line by line, the engine compiles frequently executed code into machine code, which runs faster.
JIT Compilation Process:
Parsing: JavaScript code is parsed into an Abstract Syntax Tree (AST).
Interpreter: The interpreter runs the code in its parsed form.
Profiling: The engine monitors code execution and identifies "hot" (frequently run) functions.
Optimization: "Hot" code is optimized and compiled into machine code.
Deoptimization: If assumptions about the code (e.g., types) are incorrect, the engine can revert back to the interpreted code.
8. Garbage Collection
JavaScript engines use garbage collection to automatically reclaim memory that is no longer in use by the program. This helps prevent memory leaks, where memory is consumed by unused objects.
How Garbage Collection Works:
Most JavaScript engines use a form of reference counting or mark-and-sweep algorithm to track objects in memory.
If an object is no longer referenced, it is considered unreachable and can be cleaned up by the garbage collector.
Summary
In this chapter, we covered the internal workings of JavaScript engines and runtime environments:
JavaScript engines (like V8) execute JavaScript code by parsing, interpreting, and compiling it.
The JavaScript runtime environment includes the engine, call stack, heap, event loop, and Web APIs (in the browser).
The call stack manages function calls, while the event loop ensures asynchronous code is executed after synchronous tasks complete.
Just-in-Time (JIT) compilation optimizes frequently executed code.
Garbage collection automatically manages memory, cleaning up unused objects.
Understanding these concepts helps you write more efficient JavaScript and gives you insight into how the language interacts with different environments (e.g., browsers or Node.js).