Learn JavaScript
A comprehensive JavaScript course.
Table of contents
-
Getting Started
-
Chapter I
-
Chapter II
-
Chapter III
-
Chapter IV
-
Chapter V
-
Appendix
Welcome to the comprehensive JavaScript course. JavaScript is the programming language of the web, and this course will take you from fundamentals to advanced concepts.
What is JavaScript?
JavaScript (often abbreviated as JS) is a lightweight, interpreted, or just-in-time compiled programming language with first-class functions. It is most well-known as the scripting language for Web pages, but it is also used in many non-browser environments like Node.js, Apache CouchDB, and Adobe Acrobat.
JavaScript was created in 1995 by Brendan Eich while he was working at Netscape Communications Corporation. Originally, it was designed to be a simple scripting language for adding interactivity to web pages, but it has since evolved into one of the most popular and versatile programming languages in the world.
Key Characteristics
- Multi-paradigm: JavaScript supports object-oriented, imperative, and functional programming styles.
- Dynamic typing: Variables in JavaScript are not bound to any specific type.
- Prototype-based: JavaScript uses prototypes for inheritance rather than classical inheritance.
- First-class functions: Functions in JavaScript are treated like any other variable.
- Event-driven: JavaScript can respond to events like user clicks, page loads, and more.
JavaScript Engines
All major browsers include a JavaScript engine to execute JavaScript code:
- V8: Used by Chrome and Node.js
- SpiderMonkey: Used by Firefox
- JavaScriptCore: Used by Safari
- Chakra: Used by older versions of Edge
These engines compile JavaScript to machine code for faster execution.
Why learn JavaScript?
Before we start this course, let us talk about why we should learn JavaScript.
1. Universal Language
JavaScript is the only programming language that runs natively in web browsers. It can be used for both front-end and back-end development, mobile apps, desktop applications, and even Internet of Things (IoT) devices.
2. Huge Ecosystem
The JavaScript ecosystem is massive. With npm (Node Package Manager), you have access to over a million packages that can help you build applications faster.
3. High Demand
JavaScript developers are in high demand. Whether you want to work at a startup or a large corporation, JavaScript skills are valuable in the job market.
4. Easy to Get Started
Unlike many other programming languages, JavaScript doesn't require any special installation or configuration. You can start writing JavaScript right in your browser's console.
5. Active Community
JavaScript has one of the most active developer communities. Whatever problem you're facing, there's likely an answer or solution available online.
I hope this made you excited about JavaScript. Let's start this course.
Installation and Setup
In this tutorial, we will install JavaScript and set up our development environment.
Browser
The easiest way to run JavaScript is in your web browser. All modern browsers come with built-in JavaScript engines and developer tools.
Chrome
- Download Chrome from google.com/chrome
- Install and open Chrome
- Open Developer Tools with
Cmd+Option+I(Mac) orCtrl+Shift+I(Windows/Linux) - Click on the "Console" tab
Firefox
- Download Firefox from mozilla.org
- Install and open Firefox
- Open Developer Tools with
Cmd+Option+I(Mac) orCtrl+Shift+I(Windows/Linux) - Click on the "Console" tab
VS Code
For larger projects, we recommend using Visual Studio Code.
- Download VS Code from code.visualstudio.com
- Install the "JavaScript (ES6) code snippets" extension
- Install the "Prettier" extension for code formatting
Node.js
For server-side JavaScript development, install Node.js.
- Download Node.js from nodejs.org
- Install and verify with
node --version
This is it for the installation and setup of JavaScript. Let's start the course and write our first code!
Hello World
Let's write our first JavaScript program.
Browser Console
Open your browser's developer tools and go to the Console tab. You can type JavaScript directly:
console.log("Hello World!");Press Enter to execute. You should see "Hello World!" printed in the console.
HTML File
You can also create an HTML file with embedded JavaScript:
<!DOCTYPE html>
<html>
<head>
<title>JavaScript Course</title>
</head>
<body>
<h1>Hello World</h1>
<script>
console.log("Hello World!");
</script>
</body>
</html>Node.js
If you have Node.js installed, create a file called app.js:
console.log("Hello World!");Run it in the terminal:
node app.jsCongratulations, you just wrote your first JavaScript program!
Variables and Data Types
In this tutorial, we will learn about variables and the different data types that JavaScript provides.
Variables
Let's start with declaring variables.
var
The var keyword was traditionally used to declare variables in JavaScript:
var name = "John";
console.log(name); // Johnlet
Modern JavaScript introduced let for block-scoped variables:
let age = 25;
age = 26; // Can be reassigned
console.log(age); // 26const
The const keyword is used for variables that should not be reassigned:
const PI = 3.14159;
// PI = 3.14; // Error! Cannot reassign
console.log(PI); // 3.14159Note: const doesn't make objects or arrays immutable, just prevents reassignment of the variable.
const person = { name: "John" };
person.name = "Jane"; // This works!
console.log(person); // { name: "Jane" }Data Types
JavaScript has several primitive data types:
String
Strings are used for text:
let greeting = "Hello";
let name = "World";
let template = `Hello, ${name}!`; // Template literal
console.log(greeting); // Hello
console.log(name); // World
console.log(template); // Hello, World!Number
JavaScript uses a single number type for both integers and floating-point numbers:
let integer = 42;
let decimal = 3.14;
let scientific = 2.5e6; // 2.5 million
console.log(integer); // 42
console.log(decimal); // 3.14
console.log(scientific); // 2500000Special values:
console.log(10 / 0); // Infinity
console.log(-10 / 0); // -Infinity
console.log("hello" / 2); // NaN (Not a Number)Boolean
Booleans represent true or false:
let isActive = true;
let isComplete = false;
console.log(isActive); // true
console.log(isComplete); // falseUndefined
A variable that has been declared but not assigned a value:
let undefinedVar;
console.log(undefinedVar); // undefinedNull
Represents an intentional absence of value:
let empty = null;
console.log(empty); // nullSymbol
Introduced in ES6, Symbols are unique and immutable identifiers:
const id = Symbol("id");
console.log(id); // Symbol(id)BigInt
For numbers larger than Number can safely represent:
const bigNumber = 9007199254740991n;
console.log(bigNumber); // 9007199254740991nType Checking
Use the typeof operator to check types:
console.log(typeof "hello"); // "string"
console.log(typeof 42); // "number"
console.log(typeof true); // "boolean"
console.log(typeof undefined); // "undefined"
console.log(typeof null); // "object" (historical bug)
console.log(typeof Symbol("x")); // "symbol"
console.log(typeof 123n); // "bigint"Type Coercion
JavaScript automatically converts types in certain situations:
console.log("5" + 3); // "53" (number converted to string)
console.log("5" - 3); // 2 (string converted to number)
console.log(true + 1); // 2 (true becomes 1)
console.log(false + 1); // 1 (false becomes 0)Explicit conversion:
console.log(Number("42")); // 42
console.log(String(42)); // "42"
console.log(Boolean(0)); // false
console.log(Boolean("")); // false
console.log(Boolean("hello")); // trueOperators
JavaScript provides various operators for performing operations on values.
Arithmetic Operators
let a = 10,
b = 3;
console.log(a + b); // 13 (addition)
console.log(a - b); // 7 (subtraction)
console.log(a * b); // 30 (multiplication)
console.log(a / b); // 3.333... (division)
console.log(a % b); // 1 (modulus/remainder)
console.log(a ** b); // 1000 (exponentiation)Increment and decrement:
let x = 5;
console.log(++x); // 6 (pre-increment)
console.log(x++); // 6 (post-increment, returns old value)
console.log(--x); // 5 (pre-decrement)
console.log(x--); // 5 (post-decrement, returns old value)Comparison Operators
console.log(5 == "5"); // true (loose equality, type coercion)
console.log(5 === "5"); // false (strict equality, no type coercion)
console.log(5 != "5"); // false (loose inequality)
console.log(5 !== "5"); // true (strict inequality)
console.log(5 > 3); // true
console.log(5 >= 5); // true
console.log(5 < 3); // false
console.log(5 <= 5); // trueLogical Operators
console.log(true && false); // false (AND)
console.log(true || false); // true (OR)
console.log(!true); // false (NOT)Short-circuit evaluation:
let name = null;
let defaultName = name || "Anonymous";
console.log(defaultName); // "Anonymous"
// With && - returns first falsy value or last value
console.log(false && "hello"); // false
console.log(0 && "hello"); // 0
// With || - returns first truthy value or last value
console.log("hello" || "world"); // "hello"
console.log(false || 0); // 0Assignment Operators
let x = 10;
x += 5; // x = 15
x -= 3; // x = 12
x *= 2; // x = 24
x /= 4; // x = 6
x %= 4; // x = 2
x **= 3; // x = 8Bitwise Operators
console.log(5 & 3); // 1 (AND)
console.log(5 | 3); // 7 (OR)
console.log(5 ^ 3); // 6 (XOR)
console.log(~5); // -6 (NOT)
console.log(4 << 1); // 8 (left shift)
console.log(4 >> 1); // 2 (right shift)
console.log(4 >>> 1); // 2 (unsigned right shift)Ternary Operator
Shorthand for if-else:
let age = 20;
let status = age >= 18 ? "adult" : "minor";
console.log(status); // "adult"Nullish Coalescing
Returns right side if left is null or undefined:
let value = null;
let result = value ?? "default";
console.log(result); // "default"
value = 0;
result = value ?? "default";
console.log(result); // 0Optional Chaining
Safely access nested properties:
const user = {
name: "John",
address: {
city: "New York",
},
};
console.log(user.address?.city); // "New York"
console.log(user.phone?.number); // undefined (no error)Flow Control
Let's talk about flow control statements in JavaScript.
If/Else
let score = 85;
if (score >= 90) {
console.log("A grade");
} else if (score >= 80) {
console.log("B grade");
} else if (score >= 70) {
console.log("C grade");
} else {
console.log("Need improvement");
}Switch
Useful for multiple conditions:
let day = "Monday";
switch (day) {
case "Monday":
case "Tuesday":
case "Wednesday":
case "Thursday":
case "Friday":
console.log("Weekday");
break;
case "Saturday":
case "Sunday":
console.log("Weekend");
break;
default:
console.log("Invalid day");
}For Loop
// Traditional for loop
for (let i = 0; i < 5; i++) {
console.log(i);
}
// For...of (arrays)
const fruits = ["apple", "banana", "cherry"];
for (const fruit of fruits) {
console.log(fruit);
}
// For...in (objects)
const person = { name: "John", age: 30 };
for (const key in person) {
console.log(`${key}: ${person[key]}`);
}While Loop
let count = 0;
while (count < 5) {
console.log(count);
count++;
}
// do...while (always runs at least once)
let i = 0;
do {
console.log(i);
i++;
} while (i < 5);Break and Continue
// Break - exit loop completely
for (let i = 0; i < 10; i++) {
if (i === 5) break;
console.log(i);
}
// Continue - skip to next iteration
for (let i = 0; i < 5; i++) {
if (i === 2) continue;
console.log(i);
}Exception Handling
try {
// Code that might throw an error
throw new Error("Something went wrong!");
} catch (error) {
console.log("Caught error:", error.message);
} finally {
console.log("Always executes");
}Functions
Functions are reusable blocks of code in JavaScript.
Function Declaration
function greet(name) {
return `Hello, ${name}!`;
}
console.log(greet("World")); // Hello, World!Function Expression
const greet = function (name) {
return `Hello, ${name}!`;
};
console.log(greet("World")); // Hello, World!Arrow Functions
ES6 introduced a shorter syntax:
const greet = (name) => {
return `Hello, ${name}!`;
};
// Even shorter for single expressions
const greet = (name) => `Hello, ${name}!`;
console.log(greet("World")); // Hello, World!Parameters
Default Parameters
function greet(name = "Guest") {
return `Hello, ${name}!`;
}
console.log(greet()); // Hello, Guest!
console.log(greet("John")); // Hello, John!Rest Parameters
function sum(...numbers) {
return numbers.reduce((acc, num) => acc + num, 0);
}
console.log(sum(1, 2, 3, 4, 5)); // 15Return Values
function add(a, b) {
return a + b;
}
// Functions can return functions
function multiplier(factor) {
return function (number) {
return number * factor;
};
}
const double = multiplier(2);
console.log(double(5)); // 10Higher-Order Functions
Functions can accept other functions as arguments:
function applyOperation(a, b, operation) {
return operation(a, b);
}
const result = applyOperation(5, 3, (x, y) => x + y);
console.log(result); // 8IIFE (Immediately Invoked Function Expression)
(function () {
console.log("Runs immediately!");
})();Function Scope
function outer() {
const outerVar = "I'm from outer";
function inner() {
const innerVar = "I'm from inner";
console.log(outerVar); // Accessible
console.log(innerVar); // Accessible
}
inner();
console.log(innerVar); // Error! Not accessible
}
outer();Scope and Closures
Understanding scope and closures is crucial for mastering JavaScript.
Scope
Scope determines where variables are accessible.
Global Scope
const globalVar = "I'm global";
function test() {
console.log(globalVar); // Accessible
}Function Scope
function test() {
const functionVar = "I'm function-scoped";
console.log(functionVar); // Accessible
}
test();
console.log(functionVar); // Error!Block Scope
{
const blockVar = "I'm block-scoped";
let alsoBlock = "I'm also block-scoped";
var notBlock = "I'm not block-scoped";
console.log(blockVar); // Accessible
}
console.log(blockVar); // Error!
console.log(notBlock); // Accessible (var is not block-scoped)Lexical Scope
function outer() {
const outerVar = "outer";
function inner() {
const innerVar = "inner";
console.log(outerVar); // Can access outerVar
console.log(innerVar); // Can access innerVar
}
inner();
console.log(innerVar); // Error!
}
outer();Closures
A closure is a function that remembers its outer variables even after the outer function has finished executing.
Basic Closure
function createCounter() {
let count = 0;
return function () {
count++;
return count;
};
}
const counter = createCounter();
console.log(counter()); // 1
console.log(counter()); // 2
console.log(counter()); // 3Practical Use: Private Variables
function createBankAccount(initialBalance) {
let balance = initialBalance;
return {
deposit: function (amount) {
balance += amount;
return balance;
},
withdraw: function (amount) {
if (amount <= balance) {
balance -= amount;
return balance;
}
return "Insufficient funds";
},
getBalance: function () {
return balance;
},
};
}
const account = createBankAccount(100);
console.log(account.getBalance()); // 100
account.deposit(50);
console.log(account.getBalance()); // 150
account.withdraw(30);
console.log(account.getBalance()); // 120Closure in Loops
// Problem: var doesn't create block scope
for (var i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 100);
}
// Output: 3, 3, 3 (all reference same i)
// Solution 1: Use let
for (let i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 100);
}
// Output: 0, 1, 2
// Solution 2: Use closure (IIFE)
for (var i = 0; i < 3; i++) {
(function (index) {
setTimeout(() => console.log(index), 100);
})(i);
}
// Output: 0, 1, 2this Keyword
The value of this depends on how a function is called.
Global Context
console.log(this); // Window object (in browser)Object Method
const person = {
name: "John",
greet: function () {
console.log(`Hello, I'm ${this.name}`);
},
};
person.greet(); // Hello, I'm JohnArrow Functions
Arrow functions don't have their own this:
const person = {
name: "John",
greet: () => {
console.log(`Hello, I'm ${this.name}`);
},
};
person.greet(); // Hello, I'm undefined (or Window in browser)Changing Context
const person = {
name: "John",
};
function greet() {
console.log(`Hello, I'm ${this.name}`);
}
greet.call(person); // Hello, I'm John
greet.apply(person); // Hello, I'm John
const boundGreet = greet.bind(person);
boundGreet(); // Hello, I'm JohnArrays
Arrays are ordered collections of values in JavaScript.
Creating Arrays
const numbers = [1, 2, 3, 4, 5];
const mixed = [1, "hello", true, null, { name: "John" }];
const sparse = [1, , 3]; // Contains empty slot
const fromString = Array.from("hello"); // ['h', 'e', 'l', 'l', 'o']
const withFill = Array(5).fill(0); // [0, 0, 0, 0, 0]Accessing Elements
const arr = [1, 2, 3, 4, 5];
console.log(arr[0]); // 1
console.log(arr[arr.length - 1]); // 5
console.log(arr[10]); // undefinedArray Properties
const arr = [1, 2, 3];
console.log(arr.length); // 3
arr.length = 5; // Changes array length
console.log(arr); // [1, 2, 3, undefined, undefined]Array Methods
Adding/Removing Elements
const arr = [1, 2, 3];
arr.push(4); // Add to end: [1, 2, 3, 4]
arr.pop(); // Remove from end: returns 4, array is [1, 2, 3]
arr.unshift(0); // Add to beginning: [0, 1, 2, 3]
arr.shift(); // Remove from beginning: returns 0, array is [1, 2, 3]Slicing and Splicing
const arr = [1, 2, 3, 4, 5];
// slice - returns portion (doesn't modify original)
console.log(arr.slice(1, 3)); // [2, 3]
console.log(arr.slice(-2)); // [4, 5]
// splice - removes/adds elements (modifies original)
console.log(arr.splice(1, 2, "a", "b")); // [2, 3], arr is [1, 'a', 'b', 4, 5]Searching
const arr = [1, 2, 3, 2, 4];
console.log(arr.indexOf(2)); // 1
console.log(arr.lastIndexOf(2)); // 3
console.log(arr.includes(3)); // true
console.log(arr.find((x) => x > 2)); // 3
console.log(arr.findIndex((x) => x > 2)); // 2Iteration Methods
const numbers = [1, 2, 3, 4, 5];
// forEach - execute function for each element
numbers.forEach((num, index) => console.log(`${index}: ${num}`));
// map - transform each element
const doubled = numbers.map((x) => x * 2);
console.log(doubled); // [2, 4, 6, 8, 10]
// filter - keep elements that pass test
const evens = numbers.filter((x) => x % 2 === 0);
console.log(evens); // [2, 4]
// reduce - accumulate values
const sum = numbers.reduce((acc, num) => acc + num, 0);
console.log(sum); // 15
// every - all elements pass test
console.log(numbers.every((x) => x > 0)); // true
// some - at least one element passes test
console.log(numbers.some((x) => x > 4)); // trueSorting and Reversing
const arr = [3, 1, 4, 1, 5];
console.log(arr.sort((a, b) => a - b)); // [1, 1, 3, 4, 5]
console.log(arr.reverse()); // [5, 4, 3, 1, 1]Combining
const arr1 = [1, 2];
const arr2 = [3, 4];
console.log(arr1.concat(arr2)); // [1, 2, 3, 4]
console.log([...arr1, ...arr2]); // [1, 2, 3, 4]
console.log(arr1.join("-")); // "1-2"Flattening
const nested = [1, [2, [3, [4]]]];
console.log(nested.flat()); // [1, 2, [3, [4]]]
console.log(nested.flat(2)); // [1, 2, 3, [4]]
console.log(nested.flat(Infinity)); // [1, 2, 3, 4]
// flatMap - map then flatten
const result = nested.flatMap((x) => (Array.isArray(x) ? x : [x]));
console.log(result); // [1, 2, [3, [4]]]Array Iteration
const arr = [1, 2, 3];
for (const item of arr) {
console.log(item);
}Objects
Objects are collections of key-value pairs in JavaScript.
Creating Objects
const person = {
name: "John",
age: 30,
isActive: true,
};
// Using constructor
const obj = new Object();
// Using Object.create()
const prototype = { role: "user" };
const user = Object.create(prototype);
user.name = "Jane";Accessing Properties
const person = {
name: "John",
age: 30,
address: {
city: "New York",
},
};
// Dot notation
console.log(person.name); // John
// Bracket notation
console.log(person["name"]); // John
console.log(person["address"]["city"]); // New York
// Optional chaining
console.log(person.address?.city); // New York
console.log(person.phone?.number); // undefinedAdding and Modifying
const person = { name: "John" };
person.age = 30; // Add/update
person["city"] = "NYC"; // Add/update
// Delete property
delete person.age;Object Methods
const person = {
name: "John",
age: 30,
greet() {
return `Hello, I'm ${this.name}`;
},
};
console.log(Object.keys(person)); // ['name', 'age', 'greet']
console.log(Object.values(person)); // ['John', 30, [Function: greet]]
console.log(Object.entries(person)); // [['name', 'John'], ['age', 30], ...]
console.log(Object.keys(person).length); // 3Object Descriptors
const obj = {};
// Add property with descriptors
Object.defineProperty(obj, "id", {
value: 1,
writable: false, // Cannot modify
enumerable: false, // Cannot iterate
configurable: false, // Cannot delete or redefine
});
// Get descriptors
console.log(Object.getOwnPropertyDescriptor(obj, "id"));
// Prevent modifications
const frozen = Object.freeze({ x: 1 });
// frozen.x = 2; // Error in strict mode
const sealed = Object.seal({ x: 1 });
// Cannot add/remove properties, but can modifyObject.assign
const target = { x: 1 };
const source = { y: 2 };
const result = Object.assign(target, source);
console.log(result); // { x: 1, y: 2 }
console.log(target); // { x: 1, y: 2 }Object Spread
const obj1 = { x: 1, y: 2 };
const obj2 = { ...obj1, z: 3 };
const merged = { ...obj1, ...obj2 };this in Objects
const person = {
name: "John",
greet() {
return `Hello, I'm ${this.name}`;
},
delayedGreet() {
setTimeout(function () {
console.log(this.name); // undefined (different 'this')
}, 100);
},
correctGreet() {
setTimeout(() => {
console.log(this.name); // John (inherits 'this')
}, 100);
},
};Strings
Strings are sequences of characters in JavaScript.
Creating Strings
const str1 = "Hello"; // Double quotes
const str2 = "World"; // Single quotes
const str3 = `Hello, ${str2}!`; // Template literalsString Properties and Methods
Length and Access
const str = "Hello";
console.log(str.length); // 5
console.log(str[0]); // H
console.log(str.charAt(1)); // e
console.log(str.charCodeAt(0)); // 72 (Unicode)Searching
const str = "Hello World";
console.log(str.indexOf("o")); // 4
console.log(str.lastIndexOf("o")); // 7
console.log(str.includes("World")); // true
console.log(str.startsWith("Hello")); // true
console.log(str.endsWith("World")); // true
console.log(str.search(/world/i)); // 6Extracting
const str = "Hello World";
console.log(str.slice(0, 5)); // Hello
console.log(str.slice(6)); // World
console.log(str.slice(-5)); // World
console.log(str.substring(6, 11)); // World
console.log(str.substr(6, 5)); // World (deprecated)Transforming
const str = "Hello World";
console.log(str.toUpperCase()); // HELLO WORLD
console.log(str.toLowerCase()); // hello world
console.log(" hello ".trim()); // hello
console.log("hello".padStart(10, "0")); // 0000hello
console.log("hello".padEnd(10, "0")); // hello0000
console.log("hello".repeat(3)); // hellohellohello
console.log("Hello".concat(" ", "World")); // Hello WorldSplitting and Joining
const str = "apple,banana,cherry";
console.log(str.split(",")); // ['apple', 'banana', 'cherry']
console.log(str.split("")); // ['a', 'p', 'p', 'l', 'e', ...]
console.log(["a", "b", "c"].join("-")); // a-b-cReplacing
const str = "Hello World";
console.log(str.replace("World", "JavaScript")); // Hello JavaScript
console.log(str.replace(/world/i, "JS")); // Hello JS
console.log(str.replaceAll("o", "0")); // Hell0 W0rldTemplate Literals
const name = "John";
const age = 30;
const greeting = `Hello, my name is ${name} and I am ${age} years old.`;
const calc = `2 + 2 = ${2 + 2}`;
const multiline = `
This is
a multiline
string
`;String Comparison
console.log("apple" < "banana"); // true
console.log("Apple" < "apple"); // true (uppercase comes first)
console.log("a".localeCompare("b")); // -1Destructuring
Destructuring allows you to unpack values from arrays or properties from objects into distinct variables.
Array Destructuring
const colors = ["red", "green", "blue"];
const [first, second, third] = colors;
console.log(first); // red
console.log(second); // green
console.log(third); // blue
// Skip elements
const [, , thirdColor] = colors;
console.log(thirdColor); // blue
// Rest pattern
const [primary, ...rest] = colors;
console.log(primary); // red
console.log(rest); // ['green', 'blue']
// Default values
const [a, b, c, d = "purple"] = colors;
console.log(d); // purpleObject Destructuring
const person = { name: "John", age: 30, city: "NYC" };
const { name, age } = person;
console.log(name); // John
console.log(age); // 30
// Rename variables
const { name: userName, age: userAge } = person;
// Default values
const { name, country = "USA" } = person;
// Nested destructuring
const {
address: { city },
} = { address: { city: "NYC" } };Function Parameters
function greet({ name, age }) {
return `Hello, I'm ${name} and I'm ${age} years old`;
}
console.log(greet({ name: "John", age: 30 }));
// With defaults
function createUser({ name = "Anonymous", role = "user" } = {}) {
return { name, role };
}Common Use Cases
// Swapping variables
let a = 1,
b = 2;
[a, b] = [b, a];
console.log(a, b); // 2, 1
// Ignoring return values
const [, , third] = [1, 2, 3];
// Parsing JSON
const {
name,
data: { value },
} = JSON.parse('{"name":"test","data":{"value":42}}');Spread and Rest
The spread and rest operators use the same syntax (...) but serve different purposes.
Spread Operator
Expands an iterable into individual elements.
Arrays
const arr1 = [1, 2, 3];
const arr2 = [4, 5, 6];
// Copy array
const copy = [...arr1];
console.log(copy); // [1, 2, 3]
// Concatenate
const merged = [...arr1, ...arr2];
console.log(merged); // [1, 2, 3, 4, 5, 6]
// Add elements
const withNew = [...arr1, 4, 5];
console.log(withNew); // [1, 2, 3, 4, 5]
// Copy with modification
const updated = arr1.map((x) => x * 2);
const withSpread = [...arr1.slice(0, 1), 10, ...arr1.slice(2)];Objects
const obj1 = { a: 1, b: 2 };
const obj2 = { c: 3 };
// Copy object
const copy = { ...obj1 };
console.log(copy); // { a: 1, b: 2 }
// Merge objects (later properties override)
const merged = { ...obj1, ...obj2, b: 10 };
console.log(merged); // { a: 1, b: 10, c: 3 }Function Calls
const nums = [1, 2, 3];
console.log(Math.max(...nums)); // 3
// Array to arguments
console.log(console.log(...nums)); // 1 2 3Strings
const chars = [..."hello"];
console.log(chars); // ['h', 'e', 'l', 'l', 'o']Rest Parameters
Collects remaining elements into an array.
Function Parameters
function sum(...numbers) {
return numbers.reduce((acc, n) => acc + n, 0);
}
console.log(sum(1, 2, 3, 4)); // 10
// First parameter + rest
function multiply(factor, ...numbers) {
return numbers.map((n) => n * factor);
}
console.log(multiply(2, 1, 2, 3)); // [2, 4, 6]Destructuring
const [first, ...rest] = [1, 2, 3, 4, 5];
console.log(first); // 1
console.log(rest); // [2, 3, 4, 5]
const { name, ...others } = { name: "John", age: 30, city: "NYC" };
console.log(name); // John
console.log(others); // { age: 30, city: "NYC" }With Arrow Functions
const logAll = (...args) => args.forEach((arg) => console.log(arg));
// Cannot use rest in getters but can in methods
const obj = {
getData(...args) {
return args;
},
};Symbols
Symbols are unique and immutable primitives introduced in ES6.
Creating Symbols
const sym1 = Symbol();
const sym2 = Symbol("description");
const sym3 = Symbol("description");
console.log(sym1); // Symbol()
console.log(sym2); // Symbol(description)
console.log(sym2 === sym3); // false (each Symbol is unique)Use Cases
Unique Property Keys
const user = {
[Symbol("id")]: 1,
name: "John",
};
console.log(user[Symbol("id")]); // undefined (different symbol)
console.log(Object.getOwnPropertySymbols(user)); // [Symbol(id)]Well-known Symbols
// Symbol.iterator - custom iteration
const customIterable = {
[Symbol.iterator]() {
let step = 0;
return {
next() {
step++;
if (step <= 3) {
return { value: step, done: false };
}
return { value: undefined, done: true };
},
};
},
};
for (const num of customIterable) {
console.log(num); // 1, 2, 3
}
// Symbol.toStringTag - custom toString
class MyClass {
get [Symbol.toStringTag]() {
return "MyClass";
}
}
console.log(new MyClass().toString()); // [object MyClass]
// Symbol.hasInstance - custom instanceof
class EvenNumbers {
static [Symbol.hasInstance](num) {
return num % 2 === 0;
}
}
console.log(2 instanceof EvenNumbers); // true
console.log(3 instanceof EvenNumbers); // falsePrivate Properties
const #privateMethod = Symbol("private");
const obj = {
[#privateMethod]() {
return "I'm private";
},
publicMethod() {
return this[#privateMethod]();
}
};
console.log(obj.publicMethod()); // I'm private
console.log(Object.keys(obj)); // ['publicMethod'] - private is hiddenSymbol Registry
// Global symbol registry
const sym1 = Symbol.for("myKey");
const sym2 = Symbol.for("myKey");
console.log(sym1 === sym2); // true (same symbol)
console.log(Symbol.keyFor(sym1)); // myKeyIterators and Generators
Iterators
An iterator is an object that provides a next() method returning { value, done }.
const arrayIterator = [1, 2, 3][Symbol.iterator]();
console.log(arrayIterator.next()); // { value: 1, done: false }
console.log(arrayIterator.next()); // { value: 2, done: false }
console.log(arrayIterator.next()); // { value: 3, done: false }
console.log(arrayIterator.next()); // { value: undefined, done: true }Custom Iterator
const range = {
from: 1,
to: 5,
[Symbol.iterator]() {
let current = this.from;
return {
next: () => {
if (current <= this.to) {
return { value: current++, done: false };
}
return { value: undefined, done: true };
},
};
},
};
for (const num of range) {
console.log(num); // 1, 2, 3, 4, 5
}Generators
Generators are functions that can pause and resume execution.
Basic Usage
function* simpleGenerator() {
yield 1;
yield 2;
yield 3;
}
const gen = simpleGenerator();
console.log(gen.next()); // { value: 1, done: false }
console.log(gen.next()); // { value: 2, done: false }
console.log(gen.next()); // { value: 3, done: false }
console.log(gen.next()); // { value: undefined, done: true }Generator with Loop
function* idGenerator() {
let id = 1;
while (true) {
yield id++;
}
}
const idGen = idGenerator();
console.log(idGen.next().value); // 1
console.log(idGen.next().value); // 2
console.log(idGen.next().value); // 3Infinite Sequence
function* fibonacci() {
let [a, b] = [0, 1];
while (true) {
yield a;
[a, b] = [b, a + b];
}
}
const fib = fibonacci();
console.log([...Array(10)].map(() => fib.next().value));
// [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]Delegating Generators
function* gen1() {
yield 1;
yield 2;
}
function* gen2() {
yield 3;
yield* gen1(); // Delegate to another generator
yield 4;
}
console.log([...gen2()]); // [3, 1, 2, 4]Sending Values
function* calculator() {
const result = (yield "Enter first number") + (yield "Enter second number");
yield result;
}
const calc = calculator();
console.log(calc.next().value); // "Enter first number"
console.log(calc.next(5).value); // "Enter second number"
console.log(calc.next(3).value); // 8Throwing Errors
function* errorGenerator() {
try {
yield 1;
yield 2;
} catch (e) {
yield `Error: ${e}`;
}
}
const gen = errorGenerator();
gen.next();
gen.throw("Something went wrong");Promises
Promises represent a value that may be available now, in the future, or never.
Creating Promises
const promise = new Promise((resolve, reject) => {
// Async operation
setTimeout(() => {
const success = true;
if (success) {
resolve("Operation completed");
} else {
reject(new Error("Operation failed"));
}
}, 1000);
});
promise
.then((result) => console.log(result))
.catch((error) => console.error(error));Promise States
- Pending: Initial state, neither fulfilled nor rejected
- Fulfilled: Operation completed successfully
- Rejected: Operation failed
Chaining
fetchUser(1)
.then((user) => fetchUserPosts(user.id))
.then((posts) => filterPublished(posts))
.then((published) => sortByDate(published))
.then((sorted) => displayPosts(sorted))
.catch((error) => console.error(error));Promise.all
Wait for all promises to resolve:
const promises = [
fetch("/api/users"),
fetch("/api/posts"),
fetch("/api/comments"),
];
Promise.all(promises)
.then(([users, posts, comments]) => {
console.log("All data loaded");
})
.catch((error) => {
console.error("One or more requests failed");
});Promise.race
Returns when first promise settles:
const timeout = new Promise((_, reject) =>
setTimeout(() => reject(new Error("Timeout")), 5000),
);
const request = fetch("/api/data");
Promise.race([request, timeout])
.then((data) => console.log(data))
.catch((error) => console.error(error));Promise.allSettled
Wait for all promises to settle (regardless of outcome):
const results = await Promise.allSettled([
fetch("/api/1"),
fetch("/api/2"),
fetch("/api/3"),
]);
results.forEach((result, index) => {
if (result.status === "fulfilled") {
console.log(`Request ${index}: Success`);
} else {
console.log(`Request ${index}: Failed - ${result.reason}`);
}
});Promise.any
Returns when any promise fulfills:
const promises = [
fetch("/api/1").then(() => 1),
fetch("/api/2").then(() => 2),
fetch("/api/3").then(() => 3),
];
Promise.any(promises)
.then((result) => console.log(result))
.catch((error) => console.error(error));Converting Callback to Promise
// Using Promise constructor
function promisify(callbackApi) {
return (...args) =>
new Promise((resolve, reject) => {
callbackApi(...args, (error, result) => {
if (error) reject(error);
else resolve(result);
});
});
}
// Modern: util.promisify (Node.js)
const { promisify } = require("util");
const readFile = promisify(fs.readFile);Async/Await
Async/await provides cleaner syntax for working with promises.
Basic Syntax
async function fetchData() {
try {
const response = await fetch("/api/data");
const data = await response.json();
return data;
} catch (error) {
console.error("Error:", error);
}
}Async Functions
// Function declaration
async function getData() {
return "data";
}
// Arrow function
const getData = async () => "data";
// Method
const obj = {
async getData() {
return "data";
},
};await Keyword
// Must be inside async function
async function example() {
const result = await somePromise();
console.log(result);
}Error Handling
async function fetchUser(id) {
try {
const response = await fetch(`/api/users/${id}`);
if (!response.ok) {
throw new Error(`HTTP error: ${response.status}`);
}
const user = await response.json();
return user;
} catch (error) {
console.error("Failed to fetch user:", error);
throw error; // Re-throw if needed
} finally {
console.log("Cleanup");
}
}Parallel Execution
async function fetchAll() {
// Sequential (slow)
const user = await fetchUser(1);
const posts = await fetchPosts();
// Parallel (fast)
const [user, posts] = await Promise.all([fetchUser(1), fetchPosts()]);
return { user, posts };
}Common Patterns
Sequential Await (when order matters)
async function processSteps() {
const result1 = await step1();
const result2 = await step2(result1);
const result3 = await step3(result2);
return result3;
}Concurrent with Individual Error Handling
async function fetchWithFallback(urls) {
const results = await Promise.allSettled(urls.map((url) => fetch(url)));
return results.filter((r) => r.status === "fulfilled").map((r) => r.value);
}Retry Logic
async function fetchWithRetry(url, retries = 3) {
for (let i = 0; i < retries; i++) {
try {
return await fetch(url);
} catch (error) {
if (i === retries - 1) throw error;
await new Promise((r) => setTimeout(r, 1000 * (i + 1)));
}
}
}Modules
Modules help organize JavaScript code into separate files.
CommonJS (Node.js)
// math.js
const add = (a, b) => a + b;
const subtract = (a, b) => a - b;
module.exports = { add, subtract };
// or
exports.add = add;
exports.subtract = subtract;
// main.js
const { add, subtract } = require("./math");
console.log(add(5, 3)); // 8ES Modules (Modern)
// math.js
export const add = (a, b) => a + b;
export const subtract = (a, b) => a - b;
// Default export
export default class Calculator {}
// main.js
import Calculator, { add, subtract } from "./math.js";
import * as math from "./math.js";
console.log(add(5, 3)); // 8Dynamic Imports
// Static import
import { add } from "./math.js";
// Dynamic import
const mathModule = await import("./math.js");
mathModule.add(5, 3);HTML Import
<script type="module" src="app.js"></script>Module Patterns
Re-exporting
// math/operations.js
export { add } from "./add.js";
export { subtract } from "./subtract.js";
// main.js
import { add } from "./math/operations.js";Conditional Imports
async function getModule() {
if (condition) {
return await import("./moduleA.js");
}
return await import("./moduleB.js");
}Classes
ES6 introduced a class syntax for object-oriented programming in JavaScript.
Basic Class
class Person {
// Constructor
constructor(name, age) {
this.name = name;
this.age = age;
}
// Method
greet() {
return `Hello, I'm ${this.name}`;
}
// Getter
get info() {
return `${this.name}, ${this.age} years old`;
}
// Setter
set age(value) {
if (value < 0) throw new Error("Age cannot be negative");
this._age = value;
}
// Static method
static create(name, age) {
return new Person(name, age);
}
}
const person = new Person("John", 30);
console.log(person.greet()); // Hello, I'm John
console.log(person.info); // John, 30 years old
console.log(Person.create("Jane", 25)); // Person { name: 'Jane', age: 25 }Inheritance
class Animal {
constructor(name) {
this.name = name;
}
speak() {
console.log(`${this.name} makes a sound`);
}
}
class Dog extends Animal {
constructor(name, breed) {
super(name); // Call parent constructor
this.breed = breed;
}
speak() {
super.speak(); // Call parent method
console.log(`${this.name} barks`);
}
}
const dog = new Dog("Rex", "German Shepherd");
dog.speak();
// Rex makes a sound
// Rex barksPrivate Fields
class BankAccount {
// Private field (using #)
#balance;
constructor(initialBalance) {
this.#balance = initialBalance;
}
deposit(amount) {
this.#balance += amount;
return this.#balance;
}
getBalance() {
return this.#balance;
}
}
const account = new BankAccount(100);
account.deposit(50);
console.log(account.getBalance()); // 150
console.log(account.#balance); // SyntaxErrorStatic Blocks
class MyClass {
static property = "value";
static {
// Complex initialization
this.property = this.process();
}
}Mixins
const Flyable = {
fly() {
console.log(`${this.name} flies`);
},
};
const Swimmable = {
swim() {
console.log(`${this.name} swims`);
},
};
class Duck {
constructor(name) {
this.name = name;
}
}
Object.assign(Duck.prototype, Flyable, Swimmable);
const duck = new Duck("Donald");
duck.fly(); // Donald flies
duck.swim(); // Donald swimsProxy and Reflect
Proxy
Proxy allows you to intercept and customize operations on objects.
Basic Usage
const target = { message: "Hello" };
const handler = {
get(target, prop) {
console.log(`Getting ${prop}`);
return target[prop];
},
set(target, prop, value) {
console.log(`Setting ${prop} to ${value}`);
target[prop] = value;
return true;
},
};
const proxy = new Proxy(target, handler);
proxy.message; // Getting message
proxy.message = "Hi"; // Setting message to HiProxy Traps
const handler = {
get(target, prop) {
return target[prop];
},
set(target, prop, value) {
target[prop] = value;
return true;
},
has(target, prop) {
return prop in target;
},
deleteProperty(target, prop) {
delete target[prop];
return true;
},
apply(target, thisArg, args) {
return target.apply(thisArg, args);
},
construct(target, args) {
return new target(...args);
},
};Validation
const validator = {
set(obj, prop, value) {
if (prop === "age") {
if (typeof value !== "number") {
throw new TypeError("Age must be a number");
}
if (value < 0 || value > 150) {
throw new RangeError("Invalid age");
}
}
obj[prop] = value;
return true;
},
};
const person = new Proxy({}, validator);
person.age = 30; // OK
person.age = -1; // RangeErrorPrivate Fields Pattern
const #data = new WeakMap();
class MyClass {
constructor(value) {
#data.set(this, { value });
}
getValue() {
return #data.get(this).value;
}
}Reflect
Reflect provides methods for interceptable JavaScript operations.
// Creating objects
const obj = Reflect.construct(Array, [1, 2, 3]);
// Calling functions
const result = Reflect.apply(Math.floor, undefined, [1.75]);
// Getting/Setting properties
const value = Reflect.get({ x: 1 }, "x");
Reflect.set({ x: 1 }, "x", 2);
// Checking properties
console.log(Reflect.has({ x: 1 }, "x")); // true
// Deleting properties
Reflect.deleteProperty({ x: 1 }, "x");
// Own property keys
console.log(Reflect.ownKeys({ x: 1, [Symbol("y")]: 2, z: 3 }));
// ['x', 'z', Symbol(y)]Proxy with Reflect
const target = { x: 1, y: 2 };
const proxy = new Proxy(target, {
get(target, prop) {
console.log(`Accessing ${prop}`);
return Reflect.get(target, prop);
},
set(target, prop, value) {
console.log(`Setting ${prop} = ${value}`);
return Reflect.set(target, prop, value);
},
});The DOM
The Document Object Model (DOM) represents the structure of an HTML document.
Selecting Elements
// By ID
const element = document.getElementById("myId");
// By class (returns HTMLCollection)
const elements = document.getElementsByClassName("myClass");
// By tag (returns HTMLCollection)
const paragraphs = document.getElementsByTagName("p");
// Query selectors (returns first match)
const element = document.querySelector(".myClass");
const element = document.querySelector("#myId");
const element = document.querySelector("div.container > p");
// Query selector all (returns NodeList)
const elements = document.querySelectorAll(".myClass");Modifying Elements
const element = document.querySelector("#myElement");
// Text content
element.textContent = "New text";
element.innerText = "New text (respects CSS)";
// HTML
element.innerHTML = "<strong>Bold</strong>";
// Attributes
element.setAttribute("data-id", "123");
element.getAttribute("data-id");
element.removeAttribute("data-id");
// Classes
element.classList.add("active");
element.classList.remove("hidden");
element.classList.toggle("expanded");
element.classList.contains("active");
// Styles
element.style.color = "red";
element.style.fontSize = "16px";Creating Elements
// Create element
const div = document.createElement("div");
div.textContent = "New div";
div.className = "container";
// Add to DOM
document.body.appendChild(div);
parentElement.appendChild(div);
parentElement.insertBefore(newElement, referenceElement);
// Insert adjacent HTML
element.insertAdjacentHTML("beforeend", "<span>New</span>");
// Remove
div.remove();
parentElement.removeChild(div);Traversing
const element = document.querySelector(".item");
// Parent
element.parentElement;
element.parentNode;
// Children
element.children; // HTMLCollection
element.childNodes; // NodeList (includes text nodes)
element.firstChild;
element.lastChild;
element.firstElementChild;
element.lastElementChild;
// Siblings
element.nextSibling;
element.previousSibling;
element.nextElementSibling;
element.previousElementSibling;Attributes and Data
const element = document.querySelector("#user");
// Data attributes
element.dataset.userId;
element.dataset["userId"];
// Check/remove attributes
element.hasAttribute("disabled");
element.removeAttribute("disabled");
// ClassList methods
element.classList.add("active", "highlighted");
element.classList.remove("hidden");
element.classList.toggle("expanded");
element.classList.replace("old", "new");
element.classList.contains("active");Events
Events allow you to respond to user interactions and browser actions.
Event Basics
const button = document.querySelector("button");
// Add event listener
button.addEventListener("click", function (event) {
console.log("Button clicked!");
});
// Arrow function
button.addEventListener("click", (event) => {
console.log(event.target);
});
// Named function
function handleClick(event) {
console.log("Clicked!");
}
button.addEventListener("click", handleClick);
// Remove listener
button.removeEventListener("click", handleClick);
// One-time listener
button.addEventListener(
"click",
() => {
console.log("This only fires once");
},
{ once: true },
);Common Events
Mouse Events
element.addEventListener("click", handler);
element.addEventListener("dblclick", handler);
element.addEventListener("mouseenter", handler);
element.addEventListener("mouseleave", handler);
element.addEventListener("mouseover", handler);
element.addEventListener("mouseout", handler);
element.addEventListener("mousemove", handler);
element.addEventListener("mousedown", handler);
element.addEventListener("mouseup", handler);Keyboard Events
document.addEventListener("keydown", (e) => {
console.log(e.key);
console.log(e.code);
console.log(e.ctrlKey, e.shiftKey, e.altKey);
});
document.addEventListener("keyup", handler);
document.addEventListener("keypress", handler);Form Events
form.addEventListener("submit", (e) => {
e.preventDefault(); // Prevent form submission
console.log(new FormData(form));
});
input.addEventListener("focus", handler);
input.addEventListener("blur", handler);
input.addEventListener("change", handler); // On blur if value changed
input.addEventListener("input", handler); // On every keystrokeWindow Events
window.addEventListener("resize", handler);
window.addEventListener("scroll", handler);
window.addEventListener("load", handler);
document.addEventListener("DOMContentLoaded", handler);
window.addEventListener("beforeunload", handler);Event Object
element.addEventListener("click", (event) => {
// Properties
event.target; // Element that triggered event
event.currentTarget; // Element listener is attached to
event.type; // Event type
event.bubbles; // Whether event bubbles
event.defaultPrevented; // Whether preventDefault() called
// Methods
event.preventDefault(); // Prevent default behavior
event.stopPropagation(); // Stop event from bubbling
event.stopImmediatePropagation(); // Stop all event handling
});Event Delegation
// Instead of adding listeners to each item
document.querySelector("ul").addEventListener("click", (e) => {
if (e.target.tagName === "LI") {
console.log("Clicked:", e.target.textContent);
}
});
// Bubbles up from clicked li to ulCustom Events
// Create custom event
const event = new CustomEvent("build", {
detail: { timestamp: Date.now() },
});
// Dispatch event
element.dispatchEvent(event);
// Listen for it
element.addEventListener("build", (e) => {
console.log(e.detail);
});Forms
Forms collect user input in HTML and JavaScript.
Form Structure
<form id="myForm" action="/submit" method="POST">
<label for="name">Name:</label>
<input type="text" id="name" name="name" required />
<label for="email">Email:</label>
<input type="email" id="email" name="email" />
<select name="country">
<option value="us">United States</option>
<option value="uk">United Kingdom</option>
</select>
<input type="checkbox" id="terms" name="terms" />
<label for="terms">I agree to terms</label>
<button type="submit">Submit</button>
</form>FormData API
const form = document.querySelector("#myForm");
form.addEventListener("submit", (e) => {
e.preventDefault();
// Create FormData from form element
const formData = new FormData(form);
// Methods
formData.get("name");
formData.getAll("hobbies"); // For multiple select
formData.has("email");
formData.set("name", "New Name");
formData.delete("email");
formData.append("hobbies", "reading"); // Add another value
// Convert to object
const data = Object.fromEntries(formData);
// Convert to URLSearchParams
const params = new URLSearchParams(formData);
// Fetch with FormData
fetch("/api/submit", {
method: "POST",
body: formData,
});
});Input Types
<input type="text" />
<input type="email" />
<input type="password" />
<input type="number" min="0" max="100" />
<input type="range" min="0" max="100" />
<input type="date" />
<input type="time" />
<input type="datetime-local" />
<input type="color" />
<input type="file" accept=".pdf,.doc" />
<input type="hidden" />
<textarea></textarea>
<select multiple></select>
<input type="radio" name="option" />
<input type="checkbox" name="option" value="a" />
<input type="checkbox" name="option" value="b" />Validation
HTML5 Validation
const input = document.querySelector("input");
input.checkValidity(); // Returns boolean
input.validity.valid;
input.validity.valueMissing;
input.validity.typeMismatch;
input.validity.patternMismatch;
input.validity.tooLong;
input.validity.tooShort;
input.validity.rangeUnderflow;
input.validity.rangeOverflow;
input.validity.stepMismatch;
input.validity.badInput;
input.setCustomValidity("Custom error message");
input.reportValidity();CSS Pseudo-classes
input:valid {
border-color: green;
}
input:invalid {
border-color: red;
}
input:required {
border: 2px solid;
}
input:focus:invalid {
/* ... */
}Real-time Validation
const input = document.querySelector("input[type='email']");
const error = document.querySelector(".error");
input.addEventListener("input", () => {
if (input.validity.typeMismatch) {
input.setCustomValidity("Please enter a valid email");
} else {
input.setCustomValidity("");
}
error.textContent = input.validationMessage;
});Fetch API
The Fetch API provides a modern way to make HTTP requests.
Basic Usage
fetch("https://api.example.com/data")
.then((response) => {
if (!response.ok) {
throw new Error(`HTTP error: ${response.status}`);
}
return response.json();
})
.then((data) => console.log(data))
.catch((error) => console.error(error));Async/Await
async function fetchData() {
try {
const response = await fetch("https://api.example.com/data");
if (!response.ok) {
throw new Error(`HTTP error: ${response.status}`);
}
const data = await response.json();
return data;
} catch (error) {
console.error("Fetch error:", error);
}
}Request Options
const options = {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: "Bearer token123",
},
body: JSON.stringify({ name: "John" }),
mode: "cors", // cors, no-cors, same-origin
credentials: "include", // include, same-origin, omit
cache: "no-cache",
redirect: "follow", // follow, error, manual
referrer: "no-referrer",
};
const response = await fetch(url, options);Response Properties
const response = await fetch(url);
response.ok; // true if status 200-299
response.status; // HTTP status code
response.statusText; // Status text
response.url; // Actual URL fetched
response.headers; // Headers object
response.redirected; // true if redirected
// Body methods
await response.json(); // Parse JSON
await response.text(); // Parse as text
await response.blob(); // Binary data
await response.arrayBuffer(); // ArrayBuffer
await response.formData(); // FormDataPOST Request
// JSON
const response = await fetch("/api/users", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ name: "John", email: "john@example.com" }),
});
// Form Data
const formData = new FormData(form);
const response = await fetch("/api/upload", {
method: "POST",
body: formData,
});File Upload
const input = document.querySelector('input[type="file"]');
const formData = new FormData();
for (const file of input.files) {
formData.append("files[]", file);
}
const response = await fetch("/api/upload", {
method: "POST",
body: formData,
});AbortController
const controller = new AbortController();
const signal = controller.signal;
fetch(url, { signal })
.then((response) => response.json())
.catch((err) => {
if (err.name === "AbortError") {
console.log("Request cancelled");
}
});
// Cancel after 5 seconds
setTimeout(() => controller.abort(), 5000);Parallel Requests
// Sequential
const users = await fetch("/api/users").then((r) => r.json());
const posts = await fetch("/api/posts").then((r) => r.json());
// Parallel (faster)
const [users, posts] = await Promise.all([
fetch("/api/users").then((r) => r.json()),
fetch("/api/posts").then((r) => r.json()),
]);Storage
Client-side storage mechanisms for web applications.
localStorage
// Set item
localStorage.setItem("token", "abc123");
localStorage.setItem("user", JSON.stringify({ name: "John" }));
// Get item
const token = localStorage.getItem("token");
const user = JSON.parse(localStorage.getItem("user"));
// Remove item
localStorage.removeItem("token");
// Clear all
localStorage.clear();
// Check if key exists
if (localStorage.getItem("token")) {
}
// Iterate
for (let i = 0; i < localStorage.length; i++) {
const key = localStorage.key(i);
const value = localStorage.getItem(key);
}
// Events (for cross-tab sync)
window.addEventListener("storage", (e) => {
console.log(e.key, e.oldValue, e.newValue);
});sessionStorage
// Same API as localStorage
sessionStorage.setItem("page", "1");
sessionStorage.getItem("page");
// Differences:
// - Cleared when tab/window closes
// - Data is isolated to current tabCookies
// Set cookie
document.cookie = "name=John; expires=Fri, 31 Dec 2025 23:59:59 GMT; path=/";
document.cookie = "theme=dark; max-age=3600"; // expires in 1 hour
document.cookie = "secure=true; SameSite=Strict";
// Read cookies
console.log(document.cookie); // "name=John; theme=dark"
// Parse cookies
function getCookie(name) {
const cookies = document.cookie.split("; ");
for (const cookie of cookies) {
const [key, value] = cookie.split("=");
if (key === name) return value;
}
return null;
}
// Delete cookie
document.cookie = "name=; expires=Thu, 01 Jan 1970 00:00:00 GMT";IndexedDB
// Open database
const request = indexedDB.open("MyDatabase", 1);
request.onerror = () => console.error("Database error");
request.onsuccess = () => console.log("Database opened");
request.onupgradeneeded = (e) => {
const db = e.target.result;
const store = db.createObjectStore("users", { keyPath: "id" });
store.createIndex("name", "name", { unique: false });
};
// Add data
const transaction = db.transaction(["users"], "readwrite");
const store = transaction.objectStore("users");
store.add({ id: 1, name: "John", email: "john@example.com" });
store.add({ id: 2, name: "Jane", email: "jane@example.com" });
// Get data
const getRequest = store.get(1);
getRequest.onsuccess = () => console.log(getRequest.result);
// Using with async/await
function promisifyRequest(request) {
return new Promise((resolve, reject) => {
request.onsuccess = () => resolve(request.result);
request.onerror = () => reject(request.error);
});
}Web APIs
Modern JavaScript has access to many powerful Web APIs.
Geolocation
if (navigator.geolocation) {
// Get current position
navigator.geolocation.getCurrentPosition(
(position) => {
const { latitude, longitude } = position.coords;
console.log(`Lat: ${latitude}, Long: ${longitude}`);
},
(error) => console.error(error),
{ enableHighAccuracy: true, timeout: 5000 },
);
// Watch position
const watchId = navigator.geolocation.watchPosition(
(position) => console.log(position.coords),
(error) => console.error(error),
);
// Stop watching
navigator.geolocation.clearWatch(watchId);
}Notifications
// Request permission
Notification.requestPermission().then((permission) => {
if (permission === "granted") {
new Notification("Hello!", {
body: "This is a notification",
icon: "/icon.png",
tag: "unique-id", // Replace same-tag notifications
requireInteraction: true,
});
}
});
// Service Worker notifications
self.registration.showNotification("Title", {
body: "Body text",
icon: "/icon.png",
badge: "/badge.png",
data: { url: "https://example.com" },
});Intersection Observer
const observer = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
entry.target.classList.add("visible");
}
});
},
{
root: null,
rootMargin: "0px",
threshold: 0.1,
},
);
document.querySelectorAll(".fade-in").forEach((el) => observer.observe(el));Resize Observer
const observer = new ResizeObserver((entries) => {
for (const entry of entries) {
const { width, height } = entry.contentRect;
console.log(`Size: ${width}x${height}`);
}
});
observer.observe(document.querySelector(".container"));Web Workers
// worker.js
self.onmessage = function (e) {
const result = heavyComputation(e.data);
self.postMessage(result);
};
// main.js
const worker = new Worker("worker.js");
worker.postMessage({ data: 1000 });
worker.onmessage = (e) => console.log(e.data);
worker.terminate();Broadcast Channel
// Tab 1
const channel = new BroadcastChannel("my-channel");
channel.postMessage({ type: "update", data: "hello" });
channel.onmessage = (e) => console.log(e.data);
// Tab 2 (receives the message)
const channel = new BroadcastChannel("my-channel");
channel.onmessage = (e) => console.log(e.data);Vibration
// Vibrate for 200ms
navigator.vibrate(200);
// Vibrate pattern: 100ms vibrate, 100ms pause, 200ms vibrate
navigator.vibrate([100, 100, 200]);
// Stop vibration
navigator.vibrate(0);Battery API
navigator.getBattery().then((battery) => {
console.log(`Level: ${battery.level * 100}%`);
console.log(`Charging: ${battery.charging}`);
battery.addEventListener("levelchange", () => {
console.log(`New level: ${battery.level * 100}%`);
});
});Canvas
The Canvas API allows drawing graphics using JavaScript.
Basic Setup
<canvas id="myCanvas" width="400" height="300"></canvas>const canvas = document.querySelector("#myCanvas");
const ctx = canvas.getContext("2d");
// Fill rectangle
ctx.fillStyle = "red";
ctx.fillRect(10, 10, 100, 100);
// Stroke rectangle
ctx.strokeStyle = "blue";
ctx.strokeRect(120, 10, 100, 100);
// Clear area
ctx.clearRect(0, 0, canvas.width, canvas.height);Drawing Paths
// Line
ctx.beginPath();
ctx.moveTo(0, 0);
ctx.lineTo(100, 100);
ctx.strokeStyle = "black";
ctx.lineWidth = 2;
ctx.stroke();
// Triangle
ctx.beginPath();
ctx.moveTo(50, 0);
ctx.lineTo(100, 100);
ctx.lineTo(0, 100);
ctx.closePath();
ctx.fillStyle = "green";
ctx.fill();
// Circle
ctx.beginPath();
ctx.arc(100, 100, 50, 0, Math.PI * 2);
ctx.fillStyle = "orange";
ctx.fill();
// Arc
ctx.beginPath();
ctx.arc(100, 100, 50, 0, Math.PI); // Half circle
ctx.stroke();Text
ctx.font = "24px Arial";
ctx.fillStyle = "black";
ctx.textAlign = "center";
ctx.fillText("Hello Canvas", 100, 50);
ctx.font = "16px Arial";
ctx.strokeStyle = "gray";
ctx.strokeText("Subtitle", 100, 80);Images
const img = new Image();
img.src = "image.png";
img.onload = () => {
ctx.drawImage(img, 0, 0);
// Resize
ctx.drawImage(img, 0, 0, 200, 150);
// Crop
ctx.drawImage(img, 50, 50, 100, 100, 0, 0, 100, 100);
};Transformations
// Translate
ctx.translate(50, 50);
// Rotate (radians)
ctx.rotate(Math.PI / 4);
// Scale
ctx.scale(2, 2);
// Save/restore state
ctx.save();
ctx.rotate(Math.PI / 4);
ctx.fillRect(0, 0, 50, 50);
ctx.restore();
// Reset
ctx.setTransform(1, 0, 0, 1, 0, 0);Gradients
// Linear gradient
const gradient = ctx.createLinearGradient(0, 0, 200, 0);
gradient.addColorStop(0, "red");
gradient.addColorStop(1, "blue");
ctx.fillStyle = gradient;
ctx.fillRect(0, 0, 200, 100);
// Radial gradient
const radial = ctx.createRadialGradient(100, 100, 10, 100, 100, 100);
radial.addColorStop(0, "yellow");
radial.addColorStop(1, "transparent");
ctx.fillStyle = radial;
ctx.fillRect(0, 0, 200, 200);Animation Loop
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
// Update position
x += speed;
y += speed;
// Draw
ctx.beginPath();
ctx.arc(x, y, 20, 0, Math.PI * 2);
ctx.fillStyle = "red";
ctx.fill();
requestAnimationFrame(draw);
}
requestAnimationFrame(draw);Animation
JavaScript provides several ways to create animations.
requestAnimationFrame
function animate() {
// Update positions
element.style.left = x + "px";
// Continue animation
requestAnimationFrame(animate);
}
requestAnimationFrame(animate);
// Cancel animation
const id = requestAnimationFrame(animate);
cancelAnimationFrame(id);CSS Transitions
.box {
transition: all 0.3s ease;
transform: translateX(0);
}
.box:hover {
transform: translateX(100px);
background: blue;
}element.classList.add("active");CSS Animations
@keyframes slideIn {
from {
transform: translateX(-100%);
}
to {
transform: translateX(0);
}
}
.element {
animation: slideIn 0.5s ease-out;
}element.style.animation = "slideIn 0.5s ease-out";JavaScript Animation
function animate(element, targetValue, duration = 1000) {
const start = performance.now();
function update(currentTime) {
const elapsed = currentTime - start;
const progress = Math.min(elapsed / duration, 1);
// Easing function
const easeOut = 1 - Math.pow(1 - progress, 3);
element.style.opacity = easeOut;
if (progress < 1) {
requestAnimationFrame(update);
}
}
requestAnimationFrame(update);
}GSAP Library
// Install: npm install gsap
import gsap from "gsap";
gsap.to(".box", {
x: 200,
duration: 1,
ease: "power2.out",
repeat: -1,
yoyo: true,
});
// Timeline
const tl = gsap.timeline();
tl.to(".box1", { x: 100, duration: 1 })
.to(".box2", { y: 100, duration: 1 })
.to(".box3", { rotation: 360, duration: 1 });Performance Tips
// Use transform/opacity for smooth animations
element.style.transform = `translateX(${x}px)`;
element.style.opacity = opacity;
// Use will-change (sparingly)
element.style.willChange = "transform";
element.style.willChange = "auto"; // After animation
// Use requestAnimationFrame
// NOT setTimeout or setInterval for animationsNode.js Introduction
Node.js is a JavaScript runtime built on Chrome's V8 engine that executes JavaScript outside the browser.
Installation
Download from nodejs.org or use nvm:
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.0/install.sh | bash
nvm install node
nvm use nodeBasic Server
const http = require("http");
const server = http.createServer((req, res) => {
res.writeHead(200, { "Content-Type": "text/plain" });
res.end("Hello World!");
});
server.listen(3000, () => {
console.log("Server running on port 3000");
});Node.js Modules
// CommonJS
const fs = require("fs");
const { join } = require("path");
// ES Modules (package.json: "type": "module")
import fs from "fs";
import { join } from "path";Global Objects
console.log(__dirname); // Current directory
console.log(__filename); // Current file path
console.log(process.env); // Environment variables
console.log(process.argv); // Command line arguments
setTimeout(() => {}, 1000);
setInterval(() => {}, 1000);npm and Packages
npm (Node Package Manager) is the default package manager for Node.js.
Basic Commands
# Initialize project
npm init -y
npm init
# Install package
npm install express
npm install --save express # or -S
npm install --save-dev nodemon # or -D
# Install specific version
npm install express@4.18.2
# Install from git
npm install git+https://github.com/user/repo.git
# Remove package
npm uninstall express
# Update
npm update
npm update express
# List packages
npm list
npm list --depth=0package.json
{
"name": "my-project",
"version": "1.0.0",
"description": "A sample project",
"main": "index.js",
"type": "module",
"scripts": {
"start": "node index.js",
"dev": "nodemon index.js",
"test": "jest"
},
"keywords": ["node", "express"],
"author": "John Doe",
"license": "MIT",
"dependencies": {
"express": "^4.18.2"
},
"devDependencies": {
"nodemon": "^2.0.20"
}
}npx
# Run local command
npx nodemon index.js
# Run one-time package
npx create-react-app my-appSemantic Versioning
{
"dependencies": {
"pkg": "1.2.3", // Exact version
"pkg": "^1.2.3", // 1.x.x (compatible)
"pkg": "~1.2.3", // 1.2.x (patch)
"pkg": ">=1.2.3", // At least
"pkg": "1.2.x", // Any 1.2.x
"pkg": "*" // Any version
}
}File System
Node.js fs module for working with the file system.
Reading Files
const fs = require("fs").promises;
// Async/await
async function readFile() {
const data = await fs.readFile("test.txt", "utf8");
console.log(data);
}
// Callback
fs.readFile("test.txt", "utf8", (err, data) => {
if (err) throw err;
console.log(data);
});
// Synchronous
const data = fs.readFileSync("test.txt", "utf8");Writing Files
const fs = require("fs").promises;
// Write (overwrites)
await fs.writeFile("output.txt", "Hello World", "utf8");
// Append
await fs.appendFile("output.txt", "\nMore text", "utf8");
// Write JSON
await fs.writeFile("data.json", JSON.stringify(obj, null, 2));File Operations
const fs = require("fs").promises;
// Check if exists
const exists = await fs
.access("file.txt")
.then(() => true)
.catch(() => false);
// Copy
await fs.copyFile("source.txt", "dest.txt");
// Rename
await fs.rename("old.txt", "new.txt");
// Delete
await fs.unlink("file.txt");
// Stats
const stats = await fs.stat("file.txt");
stats.isFile();
stats.isDirectory();
stats.size;
stats.mtime;Directories
const fs = require("fs").promises;
// Create directory
await fs.mkdir("new-dir", { recursive: true });
// Read directory
const files = await fs.readdir("my-dir");
// Delete directory
await fs.rmdir("empty-dir", { recursive: true });
await fs.rm("dir", { recursive: true }); // Node 14+Watch Files
const fs = require("fs");
fs.watch(".", (eventType, filename) => {
console.log(`${eventType}: ${filename}`);
});
fs.watchFile("file.txt", (curr, prev) => {
console.log("Modified");
});HTTP Server
Building HTTP servers in Node.js.
Basic HTTP Server
const http = require("http");
const server = http.createServer((req, res) => {
// Request data
console.log(req.method);
console.log(req.url);
console.log(req.headers);
// Response
res.statusCode = 200;
res.setHeader("Content-Type", "text/html");
res.end("<h1>Hello</h1>");
});
server.listen(3000, () => {
console.log("Server running");
});Handling Routes
const http = require("http");
const server = http.createServer((req, res) => {
const url = req.url;
if (url === "/") {
res.end("Home");
} else if (url === "/about") {
res.end("About");
} else {
res.writeHead(404);
res.end("Not Found");
}
});Parsing Request Body
const http = require("http");
const server = http.createServer(async (req, res) => {
if (req.method === "POST") {
let body = "";
req.on("data", (chunk) => {
body += chunk.toString();
});
req.on("end", () => {
const data = JSON.parse(body);
console.log(data);
res.end("Received");
});
}
});Request Object
req.method; // GET, POST, etc.
req.url; // URL path
req.headers; // Request headers
req.query; // Query parameters (with url module)
req.path; // URL path without query
req.protocol; // http/https
req.ip; // Client IPResponse Object
res.statusCode = 200;
res.statusMessage = "OK";
res.setHeader("Content-Type", "application/json");
res.setHeader("Cache-Control", "no-cache");
res.writeHead(200, { "Content-Type": "text/plain" });
res.write("<h1>Hello</h1>");
res.end("Done");Express.js
Express is a minimal and flexible Node.js web application framework.
Setup
npm install expressconst express = require("express");
const app = express();
app.listen(3000, () => {
console.log("Server running");
});Basic Routes
app.get("/", (req, res) => {
res.send("Home");
});
app.get("/about", (req, res) => {
res.json({ message: "About page" });
});
app.post("/api/data", (req, res) => {
res.send("POST request");
});
app.put("/api/data/:id", (req, res) => {
res.send(`Update ${req.params.id}`);
});
app.delete("/api/data/:id", (req, res) => {
res.send(`Delete ${req.params.id}`);
});Route Parameters
// Multiple params
app.get("/users/:userId/posts/:postId", (req, res) => {
const { userId, postId } = req.params;
res.json({ userId, postId });
});
// Query parameters
app.get("/search", (req, res) => {
const { q, page = 1 } = req.query;
res.json({ q, page });
});Middleware
app.use((req, res, next) => {
console.log(`${req.method} ${req.url}`);
next();
});Static Files
app.use(express.static("public"));
app.use("/static", express.static("public"));JSON and URL-encoded
app.use(express.json());
app.use(express.urlencoded({ extended: true }));Middleware
Middleware functions have access to request, response, and the next middleware.
Types of Middleware
// Application-level
app.use(logger);
// Router-level
const router = express.Router();
router.use(auth);
// Error-handling
app.use((err, req, res, next) => {
console.error(err.stack);
res.status(500).send("Something broke!");
});
// Built-in
app.use(express.json());
app.use(express.static("public"));
// Third-party
const cors = require("cors");
app.use(cors());Custom Middleware
// Logger middleware
const logger = (req, res, next) => {
console.log(`${new Date()} - ${req.method} ${req.url}`);
next();
};
// Auth middleware
const auth = (req, res, next) => {
const token = req.headers.authorization;
if (token === "valid") {
next();
} else {
res.status(401).send("Unauthorized");
}
};
// Body parser
const bodyParser = (req, res, next) => {
let body = "";
req.on("data", (chunk) => (body += chunk));
req.on("end", () => {
req.body = JSON.parse(body);
next();
});
};Middleware Order
// Execute in order
app.use(middleware1);
app.use(middleware2);
app.get("/", handler); // middleware1, middleware2, handlerRESTful APIs
Building RESTful APIs with Express.
REST Principles
- GET - Retrieve resources
- POST - Create new resources
- PUT - Update entire resources
- PATCH - Partial update
- DELETE - Remove resources
CRUD Example
const express = require("express");
const app = express();
let users = [
{ id: 1, name: "John" },
{ id: 2, name: "Jane" },
];
// GET all users
app.get("/api/users", (req, res) => {
res.json(users);
});
// GET single user
app.get("/api/users/:id", (req, res) => {
const user = users.find((u) => u.id === parseInt(req.params.id));
if (!user) return res.status(404).json({ error: "User not found" });
res.json(user);
});
// POST create user
app.post("/api/users", (req, res) => {
const newUser = {
id: users.length + 1,
name: req.body.name,
};
users.push(newUser);
res.status(201).json(newUser);
});
// PUT update user
app.put("/api/users/:id", (req, res) => {
const user = users.find((u) => u.id === parseInt(req.params.id));
if (!user) return res.status(404).json({ error: "User not found" });
user.name = req.body.name;
res.json(user);
});
// DELETE user
app.delete("/api/users/:id", (req, res) => {
const index = users.findIndex((u) => u.id === parseInt(req.params.id));
if (index === -1) return res.status(404).json({ error: "User not found" });
users.splice(index, 1);
res.status(204).send();
});Response Codes
200 OK // Success
201 Created // Resource created
204 No Content // Success, no body
400 Bad Request // Invalid input
401 Unauthorized // Not authenticated
403 Forbidden // Not authorized
404 Not Found // Resource doesn't exist
500 Internal Server Error // Server errorError Handling
Proper error handling in Express applications.
Error Classes
class AppError extends Error {
constructor(message, statusCode) {
super(message);
this.statusCode = statusCode;
this.status = `${statusCode}`.startsWith("4") ? "fail" : "error";
this.isOperational = true;
Error.captureStackTrace(this, this.constructor);
}
}
// Usage
throw new AppError("Resource not found", 404);Error Handler Middleware
// Must be last middleware
app.use((err, req, res, next) => {
err.statusCode = err.statusCode || 500;
err.status = err.status || "error";
res.status(err.statusCode).json({
status: err.status,
message: err.message,
});
});Async Error Handling
// Wrap async handlers
const asyncHandler = (fn) => (req, res, next) => {
Promise.resolve(fn(req, res, next)).catch(next);
};
app.get(
"/users",
asyncHandler(async (req, res) => {
const users = await User.findAll();
res.json(users);
}),
);Validation Errors
app.post("/users", (req, res, next) => {
const { name, email } = req.body;
if (!name || !email) {
return res.status(400).json({
error: "Name and email are required",
});
}
if (!isValidEmail(email)) {
return res.status(400).json({
error: "Invalid email format",
});
}
next();
});Testing
Testing JavaScript applications.
Jest Setup
npm install --save-dev jest// package.json
{
"scripts": {
"test": "jest"
}
}Basic Tests
// math.js
function add(a, b) {
return a + b;
}
module.exports = { add };
// math.test.js
const { add } = require("./math");
test("adds 1 + 2 to equal 3", () => {
expect(add(1, 2)).toBe(3);
});
test("adds negative numbers", () => {
expect(add(-1, -1)).toBe(-2);
});Matchers
// Equality
expect(value).toBe(expected);
expect(value).toEqual(expected);
// Truthiness
expect(value).toBeTruthy();
expect(value).toBeFalsy();
expect(value).toBeNull();
expect(value).toBeUndefined();
// Numbers
expect(value).toBeGreaterThan(3);
expect(value).toBeLessThanOrEqual(3);
// Strings
expect(value).toMatch(/pattern/);
// Arrays
expect(value).toContain(item);
expect(value).toHaveLength(3);
// Objects
expect(value).toHaveProperty("name");
expect(value).toMatchObject({ name: "John" });
// Errors
expect(() => {
throw new Error("Error!");
}).toThrow("Error!");Async Tests
test("fetches data", async () => {
const data = await fetchData();
expect(data).toHaveLength(5);
});
test("handles errors", async () => {
await expect(fetchFailingData()).rejects.toThrow("Error");
});Mocking
// Mock function
const mockFn = jest.fn();
mockFn.mockReturnValue("hello");
console.log(mockFn()); // hello
// Mock module
jest.mock("./api");
const api = require("./api");
api.fetch.mockResolvedValue({ data: "test" });
// Spy
const obj = { method: () => "real" };
jest.spyOn(obj, "method").mockReturnValue("mocked");TypeScript Introduction
TypeScript is a typed superset of JavaScript.
Setup
npm install --save-dev typescript @types/node
npx tsc --initBasic Types
let name: string = "John";
let age: number = 30;
let isActive: boolean = true;
let numbers: number[] = [1, 2, 3];
let mixed: (string | number)[] = ["a", 1];
// Type inference
let inferred = "hello"; // Type is string
// Any (avoid when possible)
let unknown: any = 4;Interfaces
interface User {
id: number;
name: string;
email?: string; // Optional
readonly createdAt: Date; // Readonly
}
const user: User = {
id: 1,
name: "John",
createdAt: new Date(),
};Types
type Status = "pending" | "active" | "completed";
type Point = {
x: number;
y: number;
};
type Callback = (data: string) => void;Functions
function greet(name: string): string {
return `Hello, ${name}`;
}
const add = (a: number, b: number): number => a + b;
// Optional parameters
function createUser(name: string, age?: number) {}
// Default parameters
function greet(name: string = "Guest") {}
// Rest parameters
function sum(...nums: number[]): number {
return nums.reduce((a, b) => a + b, 0);
}Generics
function identity<T>(arg: T): T {
return arg;
}
const result = identity<string>("hello");
interface Box<T> {
value: T;
}Build Tools
JavaScript build tools and bundlers.
Webpack
npm install webpack webpack-cli webpack-dev-server --save-dev// webpack.config.js
module.exports = {
entry: "./src/index.js",
output: {
path: __dirname + "/dist",
filename: "bundle.js",
},
mode: "development",
devtool: "source-map",
};Vite
npm create vite@latest my-app -- --template vanilla// vite.config.js
import { defineConfig } from "vite";
export default defineConfig({
server: {
port: 3000,
open: true,
},
build: {
outDir: "dist",
},
});Parcel
npm install parcel --save-dev{
"scripts": {
"start": "parcel src/index.html",
"build": "parcel build src/index.html"
}
}Performance
Optimizing JavaScript performance.
Code Splitting
// Dynamic imports
button.addEventListener("click", async () => {
const { heavyFunction } = await import("./heavy.js");
heavyFunction();
});
// React lazy loading
const LazyComponent = React.lazy(() => import("./Component"));Debouncing
function debounce(func, delay) {
let timeoutId;
return function (...args) {
clearTimeout(timeoutId);
timeoutId = setTimeout(() => {
func.apply(this, args);
}, delay);
};
}
const debouncedSearch = debounce(search, 300);
input.addEventListener("input", (e) => {
debouncedSearch(e.target.value);
});Throttling
function throttle(func, limit) {
let inThrottle;
return function (...args) {
if (!inThrottle) {
func.apply(this, args);
inThrottle = true;
setTimeout(() => (inThrottle = false), limit);
}
};
}Virtual DOM
// Simulating virtual DOM update
const elements = [];
function render() {
const virtual = elements.map((el) => createElement(el));
// Compare with actual DOM and update only changes
}Web Workers
// main.js
const worker = new Worker("worker.js");
worker.postMessage({ data: largeArray });
worker.onmessage = (e) => processResult(e.data);
// worker.js
self.onmessage = (e) => {
const result = heavyComputation(e.data);
self.postMessage(result);
};Security
Securing JavaScript applications.
XSS Prevention
// Never use innerHTML with user input
element.textContent = userInput; // Safe
element.innerText = userInput; // Safe
// Sanitize HTML
import DOMPurify from "dompurify";
element.innerHTML = DOMPurify.sanitize(userHTML);CSP Headers
// Server-side header
res.setHeader(
"Content-Security-Policy",
"default-src 'self'; script-src 'self' 'unsafe-inline';",
);Input Validation
function validateInput(input) {
// Length
if (input.length < 3 || input.length > 50) return false;
// Pattern
const pattern = /^[a-zA-Z0-9]+$/;
if (!pattern.test(input)) return false;
return true;
}HTTPS
// Always use HTTPS
if (location.protocol !== "https:") {
location.replace(`https:${location.href.slice(5)}`);
}Secure Cookies
res.cookie("session", token, {
httpOnly: true, // Cannot access via JS
secure: true, // HTTPS only
sameSite: "strict", // CSRF protection
});Design Patterns
Common design patterns in JavaScript.
Module Pattern
const Module = (function () {
let privateVar = "private";
function privateMethod() {
return privateVar;
}
return {
publicMethod: function () {
return "public";
},
getValue: function () {
return privateMethod();
},
};
})();
Module.publicMethod();
Module.getValue();Factory Pattern
class User {
constructor(options) {
this.name = options.name;
this.role = options.role;
}
}
class UserFactory {
static create(type, options) {
switch (type) {
case "admin":
return new User({ ...options, role: "admin" });
case "user":
return new User({ ...options, role: "user" });
default:
throw new Error("Invalid type");
}
}
}Observer Pattern
class Subject {
constructor() {
this.observers = [];
}
subscribe(observer) {
this.observers.push(observer);
}
unsubscribe(observer) {
this.observers = this.observers.filter((o) => o !== observer);
}
notify(data) {
this.observers.forEach((o) => o.update(data));
}
}Singleton Pattern
class Singleton {
static instance;
constructor() {
if (Singleton.instance) {
return Singleton.instance;
}
Singleton.instance = this;
this.data = 0;
}
}
const a = new Singleton();
const b = new Singleton();
console.log(a === b); // trueStrategy Pattern
class PaymentContext {
constructor(strategy) {
this.strategy = strategy;
}
pay(amount) {
return this.strategy.pay(amount);
}
}
class CreditCard {
pay(amount) {
return `Paid ${amount} via Credit Card`;
}
}
class PayPal {
pay(amount) {
return `Paid ${amount} via PayPal`;
}
}
const payment = new PaymentContext(new CreditCard());
console.log(payment.pay(100));Next Steps
Congratulations, you've finished the course!
Now that you know the fundamentals of JavaScript, here are some additional things for you to try:
- Frontend Frameworks: React, Vue, or Angular
- Backend Development: Node.js with Express or NestJS
- Mobile Development: React Native or Flutter
- Desktop Apps: Electron or Tauri
- Databases: MongoDB, PostgreSQL, or Firebase
- Testing: Jest, Mocha, or Cypress
- DevOps: Docker, CI/CD, and Cloud platforms
I hope this course was a great learning experience. I would love to hear feedback from you.
Wishing you all the best for further learning!
References
Here are the resources that were referenced while creating this course: