JavaScript Crash Course#
Table of Contents#
- 1. Modern JavaScript & Environments
- 2. Variables, Let, Const & Data Types
- 3. Operators, Equality & Type Coercion
- 4. Objects, Arrays & Destructuring
- 5. Functions, Arrow Functions & this
- 6. Scope, Hoisting & Closures
- 7. Async JS: Promises & Async/Await
- 8. Array Higher-Order Methods
- 9. Modern ES6+ Features (Nullish, Optional Chaining)
- 10. Modules: ESM vs CommonJS
- 11. Error Handling & Custom Errors
- 12. JavaScript Quick Reference
1. Modern JavaScript & Environments#
JavaScript (ECMAScript) is a dynamic, multi-paradigm, prototype-based scripting language. Originally built for web browsers, it now runs everywhere — from backend servers (Node.js, Deno, Bun) to edge workers (Cloudflare Workers, Vercel Edge).
JavaScript Runtime Components
- Engine (e.g. V8 in Chrome/Node): Compiles JavaScript into machine code using a JIT (Just-In-Time) compiler. Contains the Call Stack and Memory Heap.
- Web APIs / C++ Bindings: Features provided by the environment (DOM,
fetch(),setTimeout, file system in Node). - Event Loop: Coordinates asynchronous execution by moving callbacks from task queues into the call stack when the stack is empty.
2. Variables, Let, Const & Data Types#
Always declare variables with const by default, and let only when the variable will
be reassigned. Avoid legacy var due to its lack of block scoping.
// 1. Declaration
const PI = 3.14159; // Cannot be reassigned
let score = 0; // Block-scoped, mutable
score += 10;
// 2. JavaScript Primitives (Immutable, passed by value)
const str = "TechToday"; // String
const num = 42; // Number (64-bit float IEEE 754)
const big = 9007199254740991n; // BigInt
const bool = true; // Boolean
const undef = undefined; // Unassigned variable
const empty = null; // Intentional absence of value
const sym = Symbol("id"); // Unique primitive identifier
// 3. Complex Objects (Passed by reference)
const user = { name: "Alice", role: "Engineer" };
const tags = ["frontend", "v8", "async"];
3. Operators, Equality & Type Coercion#
Always use strict equality (===) rather than loose equality (==) to prevent silent
bugs caused by automatic type coercion:
// Loose Equality (==) -> Performs implicit coercion (AVOID)
"5" == 5; // true (string coerced to number)
0 == false; // true
null == undefined; // true
// Strict Equality (===) -> Checks both value and type (ALWAYS PREFER)
"5" === 5; // false
0 === false; // false
null === undefined; // false
// Falsy values in JavaScript:
// false, 0, -0, 0n, "", null, undefined, NaN
// Everything else is truthy (including empty arrays [] and objects {})!
4. Objects, Arrays & Destructuring#
Modern JavaScript provides clean object and array literals, destructuring, and spread/rest operators:
// Object & Array Creation
const user = {
id: 101,
username: "pankaj",
profile: { city: "San Francisco", verified: true },
skills: ["Python", "JavaScript", "Docker"]
};
// Destructuring with default values and renaming
const { username: handle, profile: { city }, age = 28 } = user;
console.log(handle, city, age); // "pankaj", "San Francisco", 28
// Array Destructuring
const [primarySkill, secondarySkill, ...restSkills] = user.skills;
console.log(primarySkill); // "Python"
console.log(restSkills); // ["Docker"]
// Object Cloning and Merging (Shallow Copy)
const updatedUser = { ...user, active: true, username: "pankaj_updated" };
5. Functions, Arrow Functions & this#
JavaScript functions are first-class citizens: they can be passed as arguments, returned from other functions, and assigned to variables.
// 1. Function Declaration (Hoisted)
function calculateTotal(price, taxRate = 0.08) {
return price + (price * taxRate);
}
// 2. Arrow Function (Lexical `this`, concise)
const double = (x) => x * 2;
// 3. Arrow function lexical `this` difference:
const timer = {
seconds: 0,
start() {
// Arrow function captures `this` from the outer `start()` scope
setInterval(() => {
this.seconds++;
}, 1000);
}
};
6. Scope, Hoisting & Closures#
A closure is the combination of a function bundled together with references to its surrounding state (the lexical environment). Closures give functions access to an outer function's scope even after the outer function has returned.
function createCounter(initialValue = 0) {
let count = initialValue; // Private variable enclosed in closure
return {
increment() { count++; return count; },
decrement() { count--; return count; },
getCount() { return count; }
};
}
const counter = createCounter(10);
console.log(counter.increment()); // 11
console.log(counter.increment()); // 12
console.log(counter.getCount()); // 12
// count variable is fully private and inaccessible from the outside!
7. Async JS: Promises & Async/Await#
JavaScript is single-threaded. Non-blocking asynchronous I/O is managed using Promises and
async/await syntax:
// 1. A Promise represents a value that will resolve or reject in the future
function fetchUserData(userId) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (userId > 0) resolve({ id: userId, name: "Alice" });
else reject(new Error("Invalid User ID"));
}, 500);
});
}
// 2. Modern Async/Await with error handling
async function loadDashboard() {
try {
const user = await fetchUserData(42);
console.log("Loaded user:", user.name);
return user;
} catch (error) {
console.error("Failed to load user:", error.message);
} finally {
console.log("Fetch attempt completed");
}
}
// 3. Parallel Async Operations with Promise.all
const [orders, products] = await Promise.all([
fetch("/api/orders").then(r => r.json()),
fetch("/api/products").then(r => r.json())
]);
8. Array Higher-Order Methods#
Functional array operations produce clean, immutable code transformations without manual for
loops:
const items = [
{ id: 1, name: "Keyboard", price: 80, inStock: true },
{ id: 2, name: "Mouse", price: 40, inStock: false },
{ id: 3, name: "Monitor", price: 300, inStock: true }
];
// map: Transform every element
const names = items.map(item => item.name); // ["Keyboard", "Mouse", "Monitor"]
// filter: Keep elements that match predicate
const available = items.filter(item => item.inStock); // Keyboard, Monitor
// reduce: Accumulate into a single value
const totalInventoryValue = items
.filter(item => item.inStock)
.reduce((sum, item) => sum + item.price, 0); // 380
// find & some & every
const monitor = items.find(item => item.id === 3);
const hasExpensive = items.some(item => item.price > 200); // true
const allInStock = items.every(item => item.inStock); // false
9. Modern ES6+ Features (Nullish, Optional Chaining)#
Modern ECMAScript provides concise operators for safely handling deep objects and default values:
// 1. Optional Chaining (?.)
const user = { profile: null };
// Safely returns undefined instead of throwing TypeError: Cannot read property of null
const avatar = user?.profile?.avatarUrl;
// 2. Nullish Coalescing (??)
// Returns right side ONLY if left is null or undefined (preserves 0 and false!)
const port = process.env.PORT ?? 3000;
const count = 0 ?? 10; // 0 (with || it would evaluate to 10!)
// 3. Logical Assignment Operators
let a = null;
a ??= "default"; // Assigns only if a is null or undefined
let b = 1;
b &&= 2; // Assigns if truthy
10. Modules: ESM vs CommonJS#
JavaScript supports two module standards: standard ECMAScript Modules (ESM) and legacy CommonJS (CJS):
// --- ECMAScript Modules (ESM - Standard) ---
// math.js
export const add = (a, b) => a + b;
export default function multiply(a, b) { return a * b; }
// app.js
import multiply, { add } from './math.js';
// --- CommonJS (CJS - Node.js legacy) ---
// math.cjs
module.exports = { add: (a, b) => a + b };
// app.cjs
const { add } = require('./math.cjs');
11. Error Handling & Custom Errors#
Robust applications use structured error handling and sub-classed error types:
class APIError extends Error {
constructor(message, statusCode) {
super(message);
this.name = "APIError";
this.statusCode = statusCode;
}
}
function processPayment(amount) {
if (amount <= 0) {
throw new APIError("Payment amount must be greater than zero", 400);
}
}
try {
processPayment(-10);
} catch (err) {
if (err instanceof APIError) {
console.error(`API Error [${err.statusCode}]: ${err.message}`);
} else {
console.error("Unknown internal error:", err);
}
}
12. JavaScript Quick Reference#
Core Rules of Thumb
- Use
constby default; useletonly when reassigning; never usevar. - Always use
===and!==to avoid implicit type conversions. - Use
??instead of||for default values when0orfalseare valid inputs. - Handle asynchronous errors using
try...catcharoundawaitexpressions. - Prefer pure array methods (
map,filter,reduce) over stateful loops.
Next Steps: Dive into the V8 engine, the event loop, microtask queues, and prototypal inheritance in the JavaScript Detailed Course. Return to the TechToday Homepage.