JavaScript — Getting Started
JavaScript (often abbreviated as JS) is a high-level, interpreted programming language that conforms to the ECMAScript specification. It is one of the three core technologies of the World Wide Web, alongside HTML and CSS, and is the only programming language natively supported by all modern web browsers.
JavaScript enables interactive web pages and is an essential part of web applications. The majority of websites use it for client-side page behavior, and all major web browsers have a dedicated JavaScript engine to execute it. Beyond the browser, JavaScript powers servers (Node.js), desktop applications (Electron), mobile apps (React Native), and even embedded systems.
Unlike other languages, JavaScript runs in an event-driven, single-threaded environment with asynchronous capabilities via the event loop. This design makes it uniquely suited for UI-intensive applications while requiring careful thinking about concurrency patterns.
| 1 | // Your first JavaScript program |
| 2 | console.log("Hello, World!"); |
| 3 | |
| 4 | // JavaScript runs in the browser's console |
| 5 | // or in any JavaScript runtime environment |
| 6 | |
| 7 | // Interactive example — try in your browser console: |
| 8 | const greeting = "Hello, World!"; |
| 9 | console.log(greeting); |
| 10 | // → Hello, World! |
JavaScript was created by Brendan Eich at Netscape in 1995 in just ten days. Originally called Mocha, then LiveScript, it was renamed JavaScript as a marketing ploy to capitalize on Java's popularity. Despite the name, JavaScript and Java are entirely different languages with different syntax, semantics, and use cases.
The language was standardized as ECMAScript in 1997. After a period of stagnation (ES4 was abandoned), the ecosystem revitalized with ES5 (2009), which introduced strict mode, JSON support, and array methods. The modern era began with ES6/ES2015, which brought classes, modules, arrow functions, promises, destructuring, and many other features.
Since ES2015, TC39 (the standards committee) has followed a yearly release cycle. Key milestones include ES2017 (async/await), ES2018 (rest/spread for objects), ES2020 (optional chaining, nullish coalescing), ES2021 (logical assignment operators), ES2023 (array find from last), and ES2024 (groupBy, Promise.withResolvers).
| Version | Year | Key Features |
|---|---|---|
| ES3 | 1999 | Regular expressions, try/catch, switch |
| ES5 | 2009 | Strict mode, JSON, Array methods (forEach, map, filter), getters/setters |
| ES6/2015 | 2015 | let/const, arrow functions, classes, modules, promises, destructuring, template literals |
| ES2016 | 2016 | Array.includes, exponentiation operator (**) |
| ES2017 | 2017 | async/await, Object.entries/values, string padding |
| ES2018 | 2018 | Rest/spread for objects, Promise.finally, async iteration |
| ES2020 | 2020 | Optional chaining (?.), nullish coalescing (??), globalThis, BigInt |
| ES2021 | 2021 | Logical assignment (&&=, ||=, ??=), String.replaceAll, Promise.any |
| ES2023 | 2023 | Array.findLast, toSpliced/toSorted/toReversed, Hashbang Grammar |
| ES2024 | 2024 | Promise.withResolvers, Object.groupBy, ArrayBuffer transfer, RegExp v flag |
info
To start writing JavaScript, you only need a web browser and a text editor. Every modern browser includes a developer console for running JavaScript interactively. For more serious development, set up Node.js and a code editor.
Browser Console
Press F12 or Ctrl+Shift+I (Windows) / Cmd+Option+I (Mac) to open DevTools. The Console tab lets you execute JavaScript in the context of any web page.
| 1 | // Try these in your browser console: |
| 2 | console.log("Hello from the console!"); |
| 3 | |
| 4 | // Inspect the current page |
| 5 | console.dir(document); |
| 6 | console.log(window.innerWidth, window.innerHeight); |
| 7 | |
| 8 | // Benchmark performance |
| 9 | console.time("loop"); |
| 10 | let sum = 0; |
| 11 | for (let i = 0; i < 1000000; i++) sum += i; |
| 12 | console.timeEnd("loop"); |
| 13 | |
| 14 | // Interactive debugging |
| 15 | const data = { name: "Alice", age: 30 }; |
| 16 | console.table(data); |
Node.js Runtime
Node.js is a JavaScript runtime built on Chrome's V8 engine. It allows you to run JavaScript on the server or command line. Install it from nodejs.org and verify with node -v.
| 1 | # Install Node.js (via nvm — recommended) |
| 2 | nvm install --lts |
| 3 | node -v |
| 4 | # → v22.x.x |
| 5 | |
| 6 | # Run a JavaScript file |
| 7 | node hello.js |
| 8 | |
| 9 | # Start a REPL (Read-Eval-Print Loop) |
| 10 | node |
| 11 | |
| 12 | # Execute inline code |
| 13 | node -e "console.log('Hello from Node!')" |
Essential Dev Tools
| Tool | Purpose |
|---|---|
| VS Code | Popular code editor with built-in JS support, debugger, and extensions |
| Chrome DevTools | Debugging, profiling, network inspection, console for live JS |
| Node.js | Server-side runtime with npm package manager |
| ESLint | Linter that catches errors and enforces code style |
| Prettier | Automatic code formatter for consistent style |
| Vite | Fast development server and build tool for modern JS projects |
best practice
Variables are used to store data values. JavaScript provides three keywords for declaring variables: var, let, and const. Modern JavaScript strongly favors const by default and let when reassignment is needed.
| Keyword | Scope | Hoisting | Reassignment | Redeclaration | Use Case |
|---|---|---|---|---|---|
| var | Function scope | Hoisted (initialized as undefined) | ✓ | ✓ | Legacy code only — avoid in modern JS |
| let | Block scope | Hoisted (not initialized — TDZ) | ✓ | ✗ | When you need to reassign the variable |
| const | Block scope | Hoisted (not initialized — TDZ) | ✗ | ✗ | Default choice — prevents reassignment |
| 1 | // const — cannot be reassigned (use by default) |
| 2 | const name = "Alice"; |
| 3 | name = "Bob"; // TypeError: Assignment to constant variable |
| 4 | |
| 5 | // const with objects — the reference is constant, not the value |
| 6 | const user = { name: "Alice" }; |
| 7 | user.name = "Bob"; // ✓ Works — mutating the object is allowed |
| 8 | user = {}; // TypeError: Assignment to constant variable |
| 9 | |
| 10 | // let — can be reassigned, block-scoped |
| 11 | let count = 0; |
| 12 | count = 1; // ✓ OK |
| 13 | let count = 2; // SyntaxError: redeclaration |
| 14 | |
| 15 | // var — function-scoped, hoisted, avoid in modern code |
| 16 | var x = 10; |
| 17 | if (true) { |
| 18 | var x = 20; // Same variable! No block scope |
| 19 | } |
| 20 | console.log(x); // 20 (var leaks out of the block) |
| 21 | |
| 22 | // Temporal Dead Zone (TDZ) |
| 23 | console.log(y); // ReferenceError: Cannot access before initialization |
| 24 | let y = 5; |
warning
JavaScript has two categories of data types: primitive types and reference types. Primitives are immutable values stored directly in the variable. Reference types store a reference to a value in memory.
Primitive Types
| Type | Example | typeof Result | Notes |
|---|---|---|---|
| string | "hello" | "string" | Single, double, or backtick quotes |
| number | 42, 3.14, NaN | "number" | 64-bit floating point (no integer type) |
| boolean | true, false | "boolean" | Logical true/false |
| undefined | undefined | "undefined" | Variable declared but not assigned |
| null | null | "object" | Intentional absence of value (typeof bug) |
| symbol | Symbol("id") | "symbol" | Unique, immutable identifier (ES6) |
| bigint | 9007199254740991n | "bigint" | Arbitrary precision integers (ES2020) |
Reference Types
Reference types store a memory address pointing to the actual data. When you assign or compare reference types, you are working with references, not the values themselves.
| 1 | // Object — collection of key-value pairs |
| 2 | const person = { |
| 3 | name: "Alice", |
| 4 | age: 30, |
| 5 | greet() { console.log(`Hi, I'm ${this.name}`); } |
| 6 | }; |
| 7 | |
| 8 | // Array — ordered list |
| 9 | const fruits = ["apple", "banana", "cherry"]; |
| 10 | fruits.push("date"); |
| 11 | console.log(fruits[0]); // "apple" |
| 12 | |
| 13 | // Function — callable value |
| 14 | function add(a, b) { return a + b; } |
| 15 | |
| 16 | // Date |
| 17 | const now = new Date(); |
| 18 | console.log(now.toISOString()); // "2026-07-07T..." |
| 19 | |
| 20 | // Map — key-value with any key types |
| 21 | const map = new Map(); |
| 22 | map.set("key", "value"); |
| 23 | |
| 24 | // Set — unique values |
| 25 | const set = new Set([1, 2, 3, 3, 3]); |
| 26 | console.log(set.size); // 3 |
| 27 | |
| 28 | // typeof pitfalls |
| 29 | console.log(typeof null); // "object" (legacy bug) |
| 30 | console.log(typeof []); // "object" |
| 31 | console.log(typeof add); // "function" |
| 32 | console.log(Array.isArray([])); // true |
info
JavaScript provides a rich set of operators for arithmetic, comparison, logical operations, and more. Understanding the nuances of each operator is essential for writing correct code.
Arithmetic Operators
| 1 | // Basic arithmetic |
| 2 | console.log(5 + 3); // 8 |
| 3 | console.log(5 - 3); // 2 |
| 4 | console.log(5 * 3); // 15 |
| 5 | console.log(5 / 3); // 1.666... |
| 6 | console.log(5 % 3); // 2 (remainder) |
| 7 | console.log(2 ** 4); // 16 (exponentiation, ES2016) |
| 8 | |
| 9 | // Increment / decrement |
| 10 | let count = 0; |
| 11 | count++; // Post-increment: returns 0, then sets to 1 |
| 12 | ++count; // Pre-increment: sets to 2, returns 2 |
| 13 | count--; // Post-decrement |
| 14 | |
| 15 | // Type coercion in arithmetic |
| 16 | console.log(1 + "2"); // "12" (string concatenation) |
| 17 | console.log("5" - 2); // 3 (coerces string to number) |
| 18 | console.log("5" * "2"); // 10 |
| 19 | console.log(+"5"); // 5 (unary plus converts to number) |
| 20 | console.log("hello" - 1); // NaN (not a number) |
| 21 | |
| 22 | // Operator precedence |
| 23 | console.log(2 + 3 * 4); // 14 (multiplication first) |
| 24 | console.log((2 + 3) * 4); // 20 (parentheses override) |
Comparison Operators
| 1 | // Strict equality (recommended) — compares value AND type |
| 2 | console.log(5 === 5); // true |
| 3 | console.log(5 === "5"); // false (number !== string) |
| 4 | |
| 5 | // Loose equality — coerces types before comparing (avoid) |
| 6 | console.log(5 == "5"); // true (coerces string to number) |
| 7 | console.log(0 == false); // true |
| 8 | console.log("" == false); // true |
| 9 | |
| 10 | // Strict inequality |
| 11 | console.log(5 !== "5"); // true |
| 12 | |
| 13 | // Relational operators |
| 14 | console.log(5 > 3); // true |
| 15 | console.log(5 <= 5); // true |
| 16 | |
| 17 | // Loose equality quirks (reasons to avoid ==) |
| 18 | console.log(null == undefined); // true |
| 19 | console.log(null === undefined); // false |
| 20 | console.log([] == false); // true |
| 21 | console.log([1] == 1); // true |
| 22 | |
| 23 | // Object comparison — references are compared, not values |
| 24 | console.log({} == {}); // false (different references) |
| 25 | console.log([] == []); // false |
Logical, Ternary & Modern Operators
| 1 | // Logical operators |
| 2 | console.log(true && false); // false (AND) |
| 3 | console.log(true || false); // true (OR) |
| 4 | console.log(!true); // false (NOT) |
| 5 | |
| 6 | // Short-circuit evaluation |
| 7 | const user = null; |
| 8 | const name = user && user.name; // null (short-circuits on falsy) |
| 9 | const fallback = user || "guest"; // "guest" |
| 10 | const sure = user ?? "guest"; // "guest" (nullish coalescing) |
| 11 | |
| 12 | // Nullish coalescing (??) — only for null/undefined, not other falsy |
| 13 | const count = 0; |
| 14 | console.log(count || 10); // 10 (0 is falsy) |
| 15 | console.log(count ?? 10); // 0 (0 is not null/undefined) |
| 16 | |
| 17 | // Ternary operator |
| 18 | const age = 20; |
| 19 | const status = age >= 18 ? "adult" : "minor"; |
| 20 | |
| 21 | // Optional chaining (?.) — safe property access |
| 22 | const data = { user: { address: null } }; |
| 23 | console.log(data.user?.address?.city); // undefined (no error) |
| 24 | console.log(data.user?.getName?.()); // undefined (optional method call) |
| 25 | |
| 26 | // Logical assignment operators (ES2021) |
| 27 | let x = 0; |
| 28 | x ||= 10; // x = x || 10 → 10 (assigns if falsy) |
| 29 | let y = 1; |
| 30 | y &&= 10; // y = y && 10 → 10 (assigns if truthy) |
| 31 | let z = null; |
| 32 | z ??= 10; // z = z ?? 10 → 10 (assigns if null/undefined) |
warning
Control flow statements determine the order in which code executes. JavaScript supports conditionals, loops, and branching constructs common to most programming languages.
Conditionals — if/else
| 1 | const score = 85; |
| 2 | |
| 3 | if (score >= 90) { |
| 4 | console.log("A"); |
| 5 | } else if (score >= 80) { |
| 6 | console.log("B"); |
| 7 | } else if (score >= 70) { |
| 8 | console.log("C"); |
| 9 | } else { |
| 10 | console.log("Failing grade"); |
| 11 | } |
| 12 | |
| 13 | // Truthiness — values that coerce to true/false |
| 14 | if ("hello") console.log("truthy"); // non-empty strings |
| 15 | if (42) console.log("truthy"); // non-zero numbers |
| 16 | if ([]) console.log("truthy"); // empty arrays (yes!) |
| 17 | if ({}) console.log("truthy"); // empty objects (yes!) |
| 18 | if (0) console.log("falsy"); // never runs |
| 19 | if ("") console.log("falsy"); // never runs |
| 20 | if (null) console.log("falsy"); // never runs |
| 21 | if (undefined) console.log("falsy"); // never runs |
| 22 | if (NaN) console.log("falsy"); // never runs |
| 23 | |
| 24 | // Early return pattern (avoids nested ifs) |
| 25 | function divide(a, b) { |
| 26 | if (b === 0) return "Cannot divide by zero"; |
| 27 | if (typeof a !== "number") return "Invalid input"; |
| 28 | return a / b; |
| 29 | } |
Switch Statement
| 1 | const day = "Wednesday"; |
| 2 | |
| 3 | switch (day) { |
| 4 | case "Monday": |
| 5 | console.log("Start of work week"); |
| 6 | break; |
| 7 | case "Wednesday": |
| 8 | case "Thursday": |
| 9 | console.log("Midweek"); |
| 10 | break; |
| 11 | case "Friday": |
| 12 | console.log("TGIF"); |
| 13 | break; |
| 14 | default: |
| 15 | console.log("Weekend"); |
| 16 | } |
| 17 | |
| 18 | // Switch with return (cleaner in functions) |
| 19 | function getDayType(day) { |
| 20 | switch (day) { |
| 21 | case "Saturday": |
| 22 | case "Sunday": |
| 23 | return "weekend"; |
| 24 | default: |
| 25 | return "weekday"; |
| 26 | } |
| 27 | } |
| 28 | |
| 29 | // Better alternative: object lookup |
| 30 | const dayTypes = { |
| 31 | Monday: "weekday", |
| 32 | Tuesday: "weekday", |
| 33 | Saturday: "weekend", |
| 34 | Sunday: "weekend", |
| 35 | }; |
| 36 | console.log(dayTypes["Monday"] ?? "invalid day"); |
Loops
| 1 | // for loop |
| 2 | for (let i = 0; i < 5; i++) { |
| 3 | console.log(i); // 0, 1, 2, 3, 4 |
| 4 | } |
| 5 | |
| 6 | // while loop |
| 7 | let i = 0; |
| 8 | while (i < 5) { |
| 9 | console.log(i); |
| 10 | i++; |
| 11 | } |
| 12 | |
| 13 | // do...while (runs at least once) |
| 14 | let j = 0; |
| 15 | do { |
| 16 | console.log(j); |
| 17 | j++; |
| 18 | } while (j < 5); |
| 19 | |
| 20 | // for...of (iterables — arrays, strings, maps, sets) |
| 21 | const fruits = ["apple", "banana", "cherry"]; |
| 22 | for (const fruit of fruits) { |
| 23 | console.log(fruit); |
| 24 | } |
| 25 | |
| 26 | // for...in (object keys — avoid for arrays) |
| 27 | const person = { name: "Alice", age: 30 }; |
| 28 | for (const key in person) { |
| 29 | console.log(`${key}: ${person[key]}`); |
| 30 | } |
| 31 | |
| 32 | // Array methods as loop alternatives |
| 33 | fruits.forEach((fruit, index) => { |
| 34 | console.log(`${index}: ${fruit}`); |
| 35 | }); |
| 36 | |
| 37 | const doubled = fruits.map(f => f.toUpperCase()); |
| 38 | const hasApple = fruits.some(f => f === "apple"); |
| 39 | const allFruits = fruits.every(f => f.length > 1); |
pro tip
Functions are the fundamental building blocks of JavaScript. They are first-class objects, meaning they can be assigned to variables, passed as arguments, and returned from other functions.
Function Declaration vs Expression vs Arrow
| Type | Hoisted | this Binding | arguments Object | Use Case |
|---|---|---|---|---|
| Declaration | ✓ Fully hoisted | Dynamic (call-site) | ✓ | Named functions, recursion, hoisting needed |
| Expression | ✗ Not hoisted | Dynamic (call-site) | ✓ | Callbacks, IIFEs, conditional definitions |
| Arrow | ✗ Not hoisted | Lexical (inherits from scope) | ✗ (use rest params) | Short callbacks, preserving this context |
| 1 | // Function declaration (hoisted — can be called before definition) |
| 2 | console.log(add(2, 3)); // 5 |
| 3 | function add(a, b) { |
| 4 | return a + b; |
| 5 | } |
| 6 | |
| 7 | // Function expression (not hoisted) |
| 8 | const subtract = function (a, b) { |
| 9 | return a - b; |
| 10 | }; |
| 11 | console.log(subtract(5, 3)); // 2 |
| 12 | |
| 13 | // Arrow function (not hoisted, implicit return for single expressions) |
| 14 | const multiply = (a, b) => a * b; |
| 15 | console.log(multiply(4, 3)); // 12 |
| 16 | |
| 17 | // Arrow with block body (explicit return needed) |
| 18 | const divide = (a, b) => { |
| 19 | if (b === 0) throw new Error("Division by zero"); |
| 20 | return a / b; |
| 21 | }; |
| 22 | |
| 23 | // Parameters and default values |
| 24 | function greet(name = "Guest", greeting = "Hello") { |
| 25 | return `${greeting}, ${name}!`; |
| 26 | } |
| 27 | console.log(greet()); // "Hello, Guest!" |
| 28 | console.log(greet("Alice")); // "Hello, Alice!" |
| 29 | console.log(greet("Bob", "Hi")); // "Hi, Bob!" |
| 30 | |
| 31 | // Rest parameters (...) |
| 32 | function sum(...numbers) { |
| 33 | return numbers.reduce((acc, n) => acc + n, 0); |
| 34 | } |
| 35 | console.log(sum(1, 2, 3, 4)); // 10 |
| 36 | |
| 37 | // First-class functions |
| 38 | const operators = { |
| 39 | add: (a, b) => a + b, |
| 40 | subtract: (a, b) => a - b, |
| 41 | multiply: (a, b) => a * b, |
| 42 | }; |
| 43 | console.log(operators.add(5, 3)); // 8 |
| 44 | |
| 45 | // Higher-order function (takes or returns a function) |
| 46 | function createMultiplier(factor) { |
| 47 | return (n) => n * factor; |
| 48 | } |
| 49 | const double = createMultiplier(2); |
| 50 | console.log(double(5)); // 10 |
| 51 | |
| 52 | // Immediately Invoked Function Expression (IIFE) |
| 53 | (function () { |
| 54 | const secret = "this is private"; |
| 55 | console.log(secret); |
| 56 | })(); |
best practice
Scope determines where variables are accessible in your code. JavaScript has global, function, and block scope. Closures are functions that retain access to their lexical scope even when executed outside that scope.
Scope Types
| 1 | // Global scope — accessible everywhere |
| 2 | const globalVar = "I'm global"; |
| 3 | |
| 4 | function demo() { |
| 5 | // Function scope — accessible within this function |
| 6 | var functionScoped = "I'm function-scoped"; |
| 7 | let blockScoped = "I'm block-scoped"; |
| 8 | |
| 9 | if (true) { |
| 10 | // Block scope — let and const are block-scoped |
| 11 | let blockVar = "Only in this block"; |
| 12 | const alsoBlock = "Also only in this block"; |
| 13 | var notBlockScoped = "I escape the block!"; // var ignores blocks |
| 14 | } |
| 15 | |
| 16 | console.log(notBlockScoped); // "I escape the block!" |
| 17 | // console.log(blockVar); // ReferenceError |
| 18 | } |
| 19 | |
| 20 | // Lexical scope — inner functions can access outer scopes |
| 21 | const outer = "outer"; |
| 22 | function parent() { |
| 23 | const middle = "middle"; |
| 24 | function child() { |
| 25 | const inner = "inner"; |
| 26 | console.log(outer); // "outer" |
| 27 | console.log(middle); // "middle" |
| 28 | console.log(inner); // "inner" |
| 29 | } |
| 30 | child(); |
| 31 | } |
| 32 | parent(); |
Closures
A closure is created when a function retains access to its enclosing scope's variables, even after the outer function has returned. This is one of JavaScript's most powerful features.
| 1 | // Basic closure — inner function keeps access to outer vars |
| 2 | function createCounter() { |
| 3 | let count = 0; // "closed over" variable |
| 4 | return function () { |
| 5 | count++; |
| 6 | return count; |
| 7 | }; |
| 8 | } |
| 9 | |
| 10 | const counter = createCounter(); |
| 11 | console.log(counter()); // 1 |
| 12 | console.log(counter()); // 2 |
| 13 | console.log(counter()); // 3 |
| 14 | |
| 15 | // Each call to createCounter creates a new closure |
| 16 | const counterA = createCounter(); |
| 17 | const counterB = createCounter(); |
| 18 | console.log(counterA()); // 1 |
| 19 | console.log(counterB()); // 1 (independent) |
| 20 | |
| 21 | // Practical: data privacy (module pattern) |
| 22 | function createBankAccount(initialBalance) { |
| 23 | let balance = initialBalance; |
| 24 | return { |
| 25 | deposit(amount) { |
| 26 | if (amount > 0) balance += amount; |
| 27 | return balance; |
| 28 | }, |
| 29 | withdraw(amount) { |
| 30 | if (amount > 0 && balance >= amount) { |
| 31 | balance -= amount; |
| 32 | return balance; |
| 33 | } |
| 34 | return "Insufficient funds"; |
| 35 | }, |
| 36 | getBalance() { |
| 37 | return balance; |
| 38 | }, |
| 39 | }; |
| 40 | } |
| 41 | |
| 42 | const account = createBankAccount(100); |
| 43 | console.log(account.getBalance()); // 100 |
| 44 | account.deposit(50); |
| 45 | console.log(account.getBalance()); // 150 |
| 46 | // console.log(account.balance); // undefined (private!) |
| 47 | |
| 48 | // Practical: function factories |
| 49 | function createGreeting(greeting) { |
| 50 | return (name) => `${greeting}, ${name}!`; |
| 51 | } |
| 52 | |
| 53 | const sayHello = createGreeting("Hello"); |
| 54 | const sayHi = createGreeting("Hi"); |
| 55 | console.log(sayHello("Alice")); // "Hello, Alice!" |
| 56 | console.log(sayHi("Bob")); // "Hi, Bob!" |
pro tip
ECMAScript 2015 (ES6) and subsequent releases introduced powerful features that make JavaScript code more concise, readable, and less error-prone. These features are now universally supported in modern environments.
Destructuring
| 1 | // Array destructuring |
| 2 | const colors = ["red", "green", "blue"]; |
| 3 | const [first, second, third] = colors; |
| 4 | console.log(first); // "red" |
| 5 | console.log(second); // "green" |
| 6 | |
| 7 | // Skip elements with commas |
| 8 | const [, , last] = colors; |
| 9 | console.log(last); // "blue" |
| 10 | |
| 11 | // Default values |
| 12 | const [a = 10, b = 20] = [5]; |
| 13 | console.log(a); // 5 |
| 14 | console.log(b); // 20 (default used) |
| 15 | |
| 16 | // Swapping variables |
| 17 | let x = 1, y = 2; |
| 18 | [x, y] = [y, x]; |
| 19 | |
| 20 | // Object destructuring |
| 21 | const person = { name: "Alice", age: 30, city: "NYC" }; |
| 22 | const { name, age } = person; |
| 23 | console.log(name); // "Alice" |
| 24 | |
| 25 | // Renaming and defaults |
| 26 | const { name: personName, country = "Unknown" } = person; |
| 27 | console.log(personName); // "Alice" |
| 28 | console.log(country); // "Unknown" |
| 29 | |
| 30 | // Nested destructuring |
| 31 | const data = { user: { id: 1, profile: { displayName: "Alice" } } }; |
| 32 | const { user: { profile: { displayName } } } = data; |
| 33 | console.log(displayName); // "Alice" |
| 34 | |
| 35 | // Destructuring parameters |
| 36 | function printUser({ name, age, city = "Unknown" }) { |
| 37 | console.log(`${name} (${age}) - ${city}`); |
| 38 | } |
| 39 | printUser(person); // "Alice (30) - NYC" |
Spread & Rest
| 1 | // Spread — expands an iterable into elements |
| 2 | const arr1 = [1, 2, 3]; |
| 3 | const arr2 = [4, 5, 6]; |
| 4 | const combined = [...arr1, ...arr2]; |
| 5 | console.log(combined); // [1, 2, 3, 4, 5, 6] |
| 6 | |
| 7 | // Copy an array (shallow) |
| 8 | const copy = [...arr1]; |
| 9 | |
| 10 | // Spread object properties |
| 11 | const base = { x: 1, y: 2 }; |
| 12 | const extended = { ...base, z: 3 }; |
| 13 | console.log(extended); // { x: 1, y: 2, z: 3 } |
| 14 | |
| 15 | // Override properties (later overrides earlier) |
| 16 | const user = { name: "Alice", role: "user" }; |
| 17 | const admin = { ...user, role: "admin" }; |
| 18 | console.log(admin); // { name: "Alice", role: "admin" } |
| 19 | |
| 20 | // Shallow copy of object |
| 21 | const cloned = { ...user }; |
| 22 | |
| 23 | // Rest parameters — collects remaining args into array |
| 24 | function logAll(first, ...rest) { |
| 25 | console.log(first); // first argument |
| 26 | console.log(rest); // array of remaining arguments |
| 27 | } |
| 28 | logAll("a", "b", "c", "d"); // first="a", rest=["b","c","d"] |
| 29 | |
| 30 | // Rest in destructuring |
| 31 | const [head, ...tail] = [1, 2, 3, 4]; |
| 32 | console.log(head); // 1 |
| 33 | console.log(tail); // [2, 3, 4] |
| 34 | |
| 35 | const { name: n, ...restProps } = { name: "Alice", age: 30, city: "NYC" }; |
| 36 | console.log(n); // "Alice" |
| 37 | console.log(restProps); // { age: 30, city: "NYC" } |
Template Literals
| 1 | // String interpolation |
| 2 | const name = "Alice"; |
| 3 | const age = 30; |
| 4 | console.log(`My name is ${name} and I am ${age} years old.`); |
| 5 | // "My name is Alice and I am 30 years old." |
| 6 | |
| 7 | // Expressions inside templates |
| 8 | console.log(`2 + 2 = ${2 + 2}`); // "2 + 2 = 4" |
| 9 | |
| 10 | // Multi-line strings (no more \n concatenation) |
| 11 | const html = ` |
| 12 | <div> |
| 13 | <h1>${name}</h1> |
| 14 | <p>Age: ${age}</p> |
| 15 | </div> |
| 16 | `; |
| 17 | |
| 18 | // Tagged templates |
| 19 | function highlight(strings, ...values) { |
| 20 | return strings.reduce((result, str, i) => { |
| 21 | const val = values[i] ? `<mark>${values[i]}</mark>` : ""; |
| 22 | return result + str + val; |
| 23 | }, ""); |
| 24 | } |
| 25 | const highlighted = highlight`User ${name} is ${age} years old.`; |
| 26 | console.log(highlighted); |
| 27 | // "User <mark>Alice</mark> is <mark>30</mark> years old." |
Optional Chaining & Nullish Coalescing
| 1 | // Before optional chaining — verbose and error-prone |
| 2 | if (data && data.user && data.user.profile) { |
| 3 | console.log(data.user.profile.name); |
| 4 | } |
| 5 | |
| 6 | // With optional chaining — clean and safe |
| 7 | console.log(data?.user?.profile?.name); // undefined (no error) |
| 8 | |
| 9 | // Optional method call |
| 10 | const result = obj?.method?.(); |
| 11 | // If obj is null/undefined, result is undefined |
| 12 | // If obj.method doesn't exist, result is undefined |
| 13 | // Otherwise, calls the method |
| 14 | |
| 15 | // Optional property access with dynamic keys |
| 16 | const key = "address"; |
| 17 | console.log(data?.user?.[key]?.city); |
| 18 | |
| 19 | // Nullish coalescing — provides default for null/undefined only |
| 20 | const timeout = config.timeout ?? 3000; |
| 21 | // Uses 3000 only if config.timeout is null or undefined |
| 22 | // If config.timeout is 0, it uses 0 (unlike ||) |
| 23 | |
| 24 | // Combining optional chaining with nullish coalescing |
| 25 | const userName = data?.user?.name ?? "Anonymous"; |
| 26 | console.log(userName); // "Anonymous" if any part is null/undefined |
| 27 | |
| 28 | // Practical: safe array access |
| 29 | const firstItem = arr?.[0] ?? "default"; |
best practice
Strict Mode
Strict mode eliminates silent errors, fixes common JavaScript pitfalls, and enables future language features. Always enable it by adding "use strict" at the top of your scripts or modules. ES modules are strict by default.
| 1 | "use strict"; |
| 2 | |
| 3 | // Silent errors become thrown errors |
| 4 | // undeclaredVar = 42; // ReferenceError (without strict: creates global) |
| 5 | // delete Object.prototype; // TypeError (without strict: silently fails) |
| 6 | |
| 7 | // this is undefined in functions instead of the global object |
| 8 | function showThis() { |
| 9 | console.log(this); // undefined (in strict mode) |
| 10 | } |
| 11 | showThis(); |
Naming Conventions
| Convention | Example | Use For |
|---|---|---|
| camelCase | userName, fetchData | Variables, functions, methods |
| PascalCase | UserProfile, ApiClient | Classes, constructors, components |
| UPPER_SNAKE | MAX_RETRIES, API_KEY | Constants, environment variables |
| _private | _internalFn, _cache | Private/internal (convention only) |
| $prefix | $el, $container | DOM references (jQuery convention) |
Essential Guidelines
Common Pitfalls
✗ Implicit Globals
function setVal() { x = 10; } // x becomes global!Always declare variables with const/let. Without strict mode, assignment to an undeclared variable creates a global.
✗ Loose Equality Surprises
console.log(false == "0"); // true (what?!)Always use === to avoid JavaScript's complex type coercion rules.
✗ Floating Point Precision
console.log(0.1 + 0.2 === 0.3); // falseUse a tolerance (Math.abs(a - b) < Number.EPSILON) or a decimal library for precise financial calculations.
✗ Async/Await Without Error Handling
async function load() { const data = await fetch(url); } // unhandled rejectionAlways wrap await calls in try/catch, or attach .catch() to promises. Unhandled rejections crash Node.js processes.
best practice