JavaScript Core
JavaScript is the only language that runs natively in every browser. Master values, functions, closures, arrays and the event loop to build on in TypeScript and React.
What is this?
JavaScript is an interpreted, prototype-based language that runs natively in browsers and on servers through Node.js. It has first-class functions, closures, and a single-threaded, event-driven concurrency model. Modern ECMAScript adds arrow functions, template literals, destructuring and native modules.
Why do you need it?
- It is the only language browsers execute, so every interactive UI on the web depends on it.
- First-class functions and closures enable powerful, composable patterns without extra syntax.
- The single-threaded event loop makes concurrency predictable and easy to reason about.
- Node.js and edge runtimes reuse the same language across server, build tooling and CLI scripts.
Mental model
A kitchen pass
The event loop
A single chef (one thread) handles orders one at a time but can start a long task like an oven and move on. When the timer rings, the chef returns to finish that order. JavaScript does the same with the task queue.
How it works
- V8 and other engines parse source to bytecode, then JIT-compile hot paths to machine code for speed.
- Values have types: primitives are immutable while objects are references stored in memory.
- Functions are objects: they capture variables from the scope they were created in, forming closures.
- The runtime runs a single-threaded loop: it executes the current task, drains the microtask queue, then pulls the next macrotask from the queue.
- async/await desugars to Promises so I/O never blocks the one thread.
How the event loop processes synchronous and asynchronous work.
Key commands
node -vCheck the installed Node.js version.
v22.x.x
node script.jsRun a JavaScript file outside the browser.
node --watch script.jsRe-run the script whenever the file changes during development.
npm init -yCreate a package.json so you can install dependencies.
Wrote to package.json ...
npx eslint script.jsLint the file and report unused variables, bugs and style issues.
node --inspect script.jsOpen the inspector so Chrome DevTools can debug the script.
Examples
Fetch data and summarize it
async function fetchUsers(url) { const response = await fetch(url); if (!response.ok) throw new Error("Request failed: " + response.status); return response.json();} function summarize(users) { const active = users .filter((user) => user.active) .map((user) => user.name.toUpperCase()); return active.length + " active users: " + active.join(", ");} fetchUsers("https://api.example.com/users") .then((data) => console.log(summarize(data))) .catch((err) => console.error(err.message));await suspends the async function until fetch resolves without blocking the thread. filter and map transform the array immutably, and the promise chain handles both success and failure paths explicitly.
In production
- Client-side interactivity: form validation, optimistic UI updates and rendering fetched data.
- Server-side work on Node.js: APIs, background jobs and build tooling such as Vite and webpack.
- The language powers edge functions on platforms like Vercel and Cloudflare Workers.
- npm hosts over a million packages, so nearly every problem already has a maintained library.
Best practices
- Use const by default and let only when you must reassign; avoid var.
- Prefer strict equality (===) so type coercion does not mask bugs.
- Write pure functions that take inputs and return outputs without mutating arguments.
- Handle every promise rejection — unhandled rejections crash apps or silently lose errors.
- Add JSDoc annotations or TypeScript types to functions with non-obvious contracts.
Common mistakes
- Forgetting await and logging a pending Promise instead of its resolved value.
- Comparing with == and relying on coercion, producing false positives like 0 == ''.
- Mutating arrays and objects in place, causing subtle aliasing bugs across components.
- Writing blocking loops over huge data on the main thread, freezing the UI.
Common issues
SyntaxError: Unexpected token '...'A syntax mistake, often a missing brace or comma, or an unclosed string.
Check the reported line and the line above it; use a linter or editor with syntax highlighting.
Unhandled promise rejectionA .then chain or try/catch does not cover every code path.
Add .catch to each chain or wrap await calls in try/catch.
ReferenceError: X is not definedThe variable was never declared, is scoped elsewhere, or the script loads before it is defined.
Declare X, move the code after its declaration, or check import paths.
Debugging tips
- console.table prints arrays of objects as a readable grid; console.time labels performance segments.
- Set breakpoints in DevTools Sources instead of scattering console.log everywhere.
- Use the Network panel to confirm fetch requests and inspect status codes and payloads.
- In Node, run with --watch and log structured data as JSON for easier grepping.
Interview checkpoint
Hands-on lab
- Read command-line arguments in Node
- Work with arrays and objects
- Use async file I/O with promises
- Handle errors gracefully
Build a CLI Task Lister
25 min · beginner
Quick quiz
Which statement correctly creates an arrow function?
Unhandled promise rejections are safe to ignore in production.
Which operator performs a strict equality check that does not coerce types?
Cheat sheet
const f = (x) => x * 2Arrow function`Hello ${name}`Template literalconst { a, b } = objObject destructuringconst [...rest] = arrArray spreadconst p = await fetch(url)Async/awaitarr.map(fn)Transform each elementarr.filter(fn)Keep matching elementsarr.reduce(fn, init)Fold to a single valuearr.find(fn)First match, or undefined