Compare

Lang Compare

JavaScript

Web

Overview

High-level, dynamic scripting language. The language of the web — runs in every browser and on the server via Node.js/Deno/Bun.

Resources

Popular learning and reference links:

Installation & Getting Started

JavaScript runs in every browser. For server-side / local development, install a runtime like Node.js, Deno, or Bun.

# Node.js — install via nvm (recommended)
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.0/install.sh | bash
nvm install --lts
node --version

# Or via Homebrew (macOS)
brew install node

# Deno — built-in TypeScript, no config needed
curl -fsSL https://deno.land/install.sh | sh
deno --version

# Bun — fast all-in-one runtime
curl -fsSL https://bun.sh/install | bash
bun --version
# REPL — start an interactive session
node           # Node.js REPL
deno           # Deno REPL
bun repl       # Bun REPL

# Run a script
node script.js
deno run script.js
bun run script.js

# Quick one-liner
node -e "console.log('Hello!')"

Project Scaffolding

Use npm init for a basic project or a framework CLI for a full setup.

# Basic project
mkdir my-project && cd my-project
npm init -y

# Using Vite
npm create vite@latest my-app

# Using Next.js
npx create-next-app@latest my-app

# Using Astro
npm create astro@latest

# Run the project
npm run dev

Package Management

npm is the default package manager. Yarn, pnpm, and Bun are popular alternatives.

# Install a package
npm install lodash

# Install as dev dependency
npm install --save-dev vitest

# Install globally
npm install -g typescript

# Using pnpm
pnpm add lodash

# Using yarn
yarn add lodash

# Using bun
bun add lodash

Tooling & Formatter/Linter

Rich ecosystem of formatters and linters. Most projects use a combination.

# Prettier — opinionated code formatter
npm install --save-dev prettier
npx prettier --write .

# ESLint — linting and code quality
npm install --save-dev eslint
npx eslint --init
npx eslint .

# Biome — fast all-in-one (format + lint)
npm install --save-dev @biomejs/biome
npx biome check --write .

# oxlint — extremely fast linter (Rust-based)
npx oxlint .
// .prettierrc
{
  "semi": false,
  "singleQuote": true,
  "trailingComma": "all",
  "printWidth": 100
}
// eslint.config.js (flat config)
import js from '@eslint/js'
export default [
  js.configs.recommended,
  { rules: { 'no-unused-vars': 'warn' } },
]

Build & Compile Model

Interpreted / JIT-compiled. JavaScript is parsed and JIT-compiled at runtime by the engine (V8, SpiderMonkey, JavaScriptCore).

# No compile step — run directly
node app.js
deno run app.js
bun run app.js

# Bundling for browsers (not compilation, but required)
npx vite build         # Vite (esbuild + Rollup)
npx esbuild app.js --bundle --outfile=out.js
npx webpack            # webpack

# Output: .js bundles, source maps
# No binary output — always JavaScript

Execution model:

  • Source → Parse → AST → Bytecode → JIT machine code
  • V8 uses TurboFan (optimizing compiler) and Sparkplug (baseline)
  • No ahead-of-time compilation (except experimental with Hermes, QuickJS)
  • Tree-shaking and dead-code elimination happen at bundle time, not compile time

Libraries & Frameworks

JavaScript has an enormous ecosystem. Key libraries and frameworks by category:

Web Frameworks - React, Vue, Svelte, Angular, Solid, Astro, Next.js, Nuxt, SvelteKit, Remix

Server / API - Express, Fastify, Hono, Koa, Nest.js, tRPC

Build Tools - Vite, esbuild, Rollup, webpack, Turbopack, Parcel

State Management - Zustand, Jotai, Redux Toolkit, Pinia (Vue), Signals

Styling - Tailwind CSS, Styled Components, CSS Modules, UnoCSS

Databases / ORM - Prisma, Drizzle, Mongoose, Knex, TypeORM

Utilities - Lodash, date-fns, Zod, Axios, Ramda

Testing - Vitest, Jest, Playwright, Cypress, Testing Library

Desktop - Electron, Tauri

Mobile - React Native, Expo, Capacitor, NativeScript

Testing

Popular testing frameworks include Vitest, Jest, and the built-in Node.js test runner. Playwright and Cypress are used for end-to-end testing.

// Vitest (recommended — fast, Vite-native)
import { describe, it, expect } from 'vitest'

describe('math', () => {
  it('adds numbers', () => {
    expect(1 + 2).toBe(3)
  })

  it('handles arrays', () => {
    expect([1, 2, 3]).toContain(2)
    expect([1, 2, 3]).toHaveLength(3)
  })
})
// Node.js built-in test runner (v18+)
import { describe, it } from 'node:test'
import assert from 'node:assert'

describe('math', () => {
  it('adds numbers', () => {
    assert.strictEqual(1 + 2, 3)
  })
})
# Run tests
npx vitest           # Vitest (watch mode)
npx vitest run       # Vitest (single run)
npx jest             # Jest
node --test          # Node.js built-in

# E2E testing
npx playwright test  # Playwright
npx cypress run      # Cypress

Debugging

Chrome DevTools for browser, Node.js inspector for server. console methods and debugger statement.

// console methods
console.log('basic log')
console.error('error message')
console.warn('warning')
console.table([{ name: 'Alice', age: 30 }])
console.dir(obj, { depth: null })
console.time('op'); doWork(); console.timeEnd('op')
console.trace('call stack')
console.group('section'); /* ... */ console.groupEnd()

// debugger statement — triggers breakpoint
function processData(data) {
  debugger  // Pauses here if DevTools is open
  return data.map(transform)
}
# Node.js debugging
node --inspect app.js          # Start with inspector
node --inspect-brk app.js     # Break on first line
# Open chrome://inspect in Chrome

# VS Code — built-in debugger
# launch.json:
{
  "type": "node",
  "request": "launch",
  "program": "${workspaceFolder}/src/index.js",
  "console": "integratedTerminal"
}
# Set breakpoints by clicking gutter
# F5 to start, F10 step over, F11 step into

# Chrome DevTools
# Sources tab: breakpoints, watch, call stack
# Network tab: request/response inspection
# Console tab: live REPL in page context
# Elements tab: DOM inspection

# ndb — improved Node.js debugging
npx ndb node app.js

Variables

Use const for immutable bindings and let for mutable ones. var is legacy and function-scoped.

const name = 'Alice';
let age = 30;
var legacy = true; // function-scoped, avoid

// Destructuring
const { x, y } = { x: 1, y: 2 };
const [first, ...rest] = [1, 2, 3];

Types

JavaScript is dynamically typed. Primitives: string, number, boolean, null, undefined, symbol, bigint.

typeof 'hello';    // "string"
typeof 42;         // "number"
typeof true;       // "boolean"
typeof undefined;  // "undefined"
typeof null;       // "object" (legacy bug)
typeof Symbol();   // "symbol"
typeof 42n;        // "bigint"

// Arrays and objects
const arr = [1, 2, 3];
const obj = { key: 'value' };

Data Structures

Built-in: Arrays, Objects, Map, Set, WeakMap, WeakSet. No built-in linked list, queue, or stack types.

// Arrays — ordered, mixed types
const arr = [1, 'two', true]
arr.push(4)
arr.pop()
arr.includes(1)           // true
arr.find(x => x === 'two')
arr.slice(0, 2)           // [1, 'two']

// Objects — key-value (string keys)
const obj = { name: 'Alice', age: 30 }
obj.email = 'a@b.com'
delete obj.age
Object.keys(obj)          // ['name', 'email']
Object.entries(obj)       // [['name','Alice'], ...]

// Map — key-value (any key type, ordered)
const map = new Map()
map.set('key', 'value')
map.set(42, 'number key')
map.get('key')            // 'value'
map.has(42)               // true
map.size                  // 2

// Set — unique values
const set = new Set([1, 2, 3, 3])
set.add(4)
set.has(2)                // true
set.size                  // 4

// WeakMap / WeakSet — garbage-collectable keys
const wm = new WeakMap()
wm.set(someObj, 'metadata')

// Typed arrays (for binary data)
const buf = new ArrayBuffer(16)
const view = new Int32Array(buf)

Functions

Functions can be declared, expressed, or written as arrow functions.

// Function declaration
function greet(name) {
  return `Hello, ${name}!`;
}

// Arrow function
const add = (a, b) => a + b;

// Default parameters
function power(base, exp = 2) {
  return base ** exp;
}

// Rest parameters
function sum(...nums) {
  return nums.reduce((a, b) => a + b, 0);
}

Conditionals

Standard if/else, ternary operator, and switch.

// If / else
if (x > 0) {
  console.log('positive');
} else if (x === 0) {
  console.log('zero');
} else {
  console.log('negative');
}

// Ternary
const label = x > 0 ? 'positive' : 'non-positive';

// Switch
switch (color) {
  case 'red':
    console.log('#f00');
    break;
  case 'blue':
    console.log('#00f');
    break;
  default:
    console.log('unknown');
}

// Nullish coalescing
const val = input ?? 'default';

// Optional chaining
const city = user?.address?.city;

Loops

Standard for, while, and iterator-based loops.

// For loop
for (let i = 0; i < 5; i++) {
  console.log(i);
}

// For...of (iterables)
for (const item of [1, 2, 3]) {
  console.log(item);
}

// For...in (object keys)
for (const key in { a: 1, b: 2 }) {
  console.log(key);
}

// While
let n = 0;
while (n < 3) {
  n++;
}

// Array methods
[1, 2, 3].forEach((x) => console.log(x));
[1, 2, 3].map((x) => x * 2);

Generics & Type System

JavaScript has no type system at runtime. Types are dynamic — any variable can hold any value. Use TypeScript for static types.

// No generics — functions work with any type naturally
function identity(x) { return x }
identity(42)       // number
identity('hello')  // string

// Duck typing — if it has the right shape, it works
function getLength(thing) {
  return thing.length  // Works for strings, arrays, etc.
}

// typeof — runtime type checking
typeof 42          // 'number'
typeof 'hello'     // 'string'
typeof true        // 'boolean'
typeof undefined   // 'undefined'
typeof null        // 'object' (historical bug)
typeof {}          // 'object'
typeof []          // 'object'

// instanceof — check prototype chain
[] instanceof Array     // true
new Date() instanceof Date  // true

// Array.isArray — reliable array check
Array.isArray([1, 2])  // true

JavaScript is dynamically typed — generics are a TypeScript concept. See the TypeScript column for full generics support.

Inheritance & Composition

Prototypal inheritance with class syntax sugar. Composition via mixins and object spread is often preferred.

// Class inheritance
class Animal {
  constructor(name) { this.name = name }
  speak() { return `${this.name} makes a sound` }
}

class Dog extends Animal {
  speak() { return `${this.name} barks` }
}

// Super calls
class Puppy extends Dog {
  constructor(name) {
    super(name)
    this.young = true
  }
}

// Mixins (composition pattern)
const Serializable = (Base) => class extends Base {
  toJSON() { return JSON.stringify(this) }
}

class User extends Serializable(Animal) {}

// Object composition (preferred)
const canWalk = (state) => ({
  walk: () => `${state.name} walks`,
})
const canSwim = (state) => ({
  swim: () => `${state.name} swims`,
})
const createDuck = (name) => {
  const state = { name }
  return { ...canWalk(state), ...canSwim(state) }
}

Functional Patterns

First-class functions, closures, and a rich set of array methods for functional programming.

// Higher-order functions
const apply = (fn, x) => fn(x)
const double = (x) => x * 2
apply(double, 5) // 10

// Map, filter, reduce
const nums = [1, 2, 3, 4, 5]
const squared = nums.map((x) => x * x)
const evens = nums.filter((x) => x % 2 === 0)
const sum = nums.reduce((acc, x) => acc + x, 0)

// Function composition
const compose = (f, g) => (x) => f(g(x))
const addOne = (x) => x + 1
const doubleAndAdd = compose(addOne, double)

// Closures
function counter(start = 0) {
  let count = start
  return { inc: () => ++count, get: () => count }
}

// Currying
const add = (a) => (b) => a + b
const add5 = add(5)
add5(3) // 8

// Chaining
const result = [1, 2, 3, 4, 5]
  .filter((x) => x > 2)
  .map((x) => x * 10)
  .reduce((a, b) => a + b, 0)

Concurrency

Single-threaded event loop with async/await. Web Workers and worker_threads provide true parallelism.

// async/await — non-blocking I/O
async function fetchData() {
  const res = await fetch('/api/data')
  return res.json()
}

// Promise.all — concurrent requests
const [users, posts] = await Promise.all([
  fetch('/api/users').then(r => r.json()),
  fetch('/api/posts').then(r => r.json()),
])

// Promise.allSettled — don't fail on one rejection
const results = await Promise.allSettled([
  fetch('/api/a'),
  fetch('/api/b'),
])

// setTimeout / setInterval
setTimeout(() => console.log('delayed'), 1000)
// Worker threads (Node.js) — true parallelism
import { Worker, isMainThread, parentPort } from 'worker_threads'

if (isMainThread) {
  const worker = new Worker(new URL(import.meta.url))
  worker.on('message', (msg) => console.log(msg))
  worker.postMessage('start')
} else {
  parentPort.on('message', () => {
    parentPort.postMessage('done')
  })
}

// Web Workers (browser) — similar API
// const worker = new Worker('worker.js')

Modules & Imports

ES Modules (ESM) are the standard. CommonJS (CJS) is legacy but still used in Node.js. Bundlers like Vite, esbuild, and webpack handle bundling for the browser.

// Named exports
export const PI = 3.14
export function add(a, b) { return a + b }

// Default export
export default class App {}

// Named imports
import { add, PI } from './math.js'

// Default import
import App from './App.js'

// Rename imports
import { add as sum } from './math.js'

// Import everything
import * as math from './math.js'

// Dynamic import (code splitting)
const module = await import('./heavy.js')

// Re-export
export { add } from './math.js'
export { default } from './App.js'

// CommonJS (Node.js legacy)
const fs = require('fs')
module.exports = { add }

Error Handling

Use try/catch/finally for synchronous and async error handling.

// Try / catch
try {
  JSON.parse('invalid');
} catch (error) {
  console.error('Parse failed:', error.message);
} finally {
  console.log('always runs');
}

// Throwing errors
function divide(a, b) {
  if (b === 0) throw new Error('Division by zero');
  return a / b;
}

// Async error handling
try {
  const res = await fetch('/api');
  const data = await res.json();
} catch (err) {
  console.error('Fetch failed:', err);
}

// Promise catch
fetch('/api')
  .then((res) => res.json())
  .catch((err) => console.error(err));

Memory Management

Garbage collected. V8 uses a generational GC (Scavenger for young gen, Mark-Sweep/Mark-Compact for old gen). No manual memory management.

// Memory is automatically allocated and freed
let obj = { name: 'Alice' }  // Allocated on heap
obj = null                     // Eligible for GC

// WeakRef — reference that doesn't prevent GC
let target = { data: 'important' }
const weak = new WeakRef(target)
weak.deref()  // { data: 'important' } or undefined

// FinalizationRegistry — callback when object is GC'd
const registry = new FinalizationRegistry((value) => {
  console.log(`${value} was garbage collected`)
})
registry.register(target, 'my-target')

// WeakMap / WeakSet — keys are weakly held
const cache = new WeakMap()
cache.set(someObj, expensiveResult)
// When someObj is GC'd, the entry is removed

Common memory issues:

  • Closures retaining references longer than needed
  • Event listeners not removed (use AbortController)
  • Detached DOM nodes still referenced in JS
  • Large arrays/buffers — use streaming or ArrayBuffer
  • Timers (setInterval) not cleared

Use Chrome DevTools → Memory tab to profile heap snapshots and detect leaks.

Performance Profiling

Chrome DevTools and Node.js built-in profiler are the primary tools. performance.now() for manual timing.

// Manual timing
const start = performance.now()
doExpensiveWork()
console.log(`Took ${performance.now() - start}ms`)

// console.time / console.timeEnd
console.time('fetch')
await fetch('/api/data')
console.timeEnd('fetch')  // fetch: 142.3ms

// Performance API (browser)
performance.mark('start')
doWork()
performance.mark('end')
performance.measure('work', 'start', 'end')
console.log(performance.getEntriesByName('work'))
# Node.js built-in profiler
node --prof app.js
node --prof-process isolate-*.log > profile.txt

# Node.js inspector (CPU + heap profiling)
node --inspect app.js
# Open chrome://inspect in Chrome

# Clinic.js — Node.js performance toolkit
npx clinic doctor -- node app.js
npx clinic flame -- node app.js
npx clinic bubbleprof -- node app.js

# Chrome DevTools
# Performance tab: CPU flame chart, call tree
# Memory tab: heap snapshots, allocation timeline
# Lighthouse: web performance auditing

Interop

JavaScript interops with native code via N-API/node-addon-api (Node.js), WebAssembly, and Web APIs (browser).

// WebAssembly — run compiled code in JS
const wasmModule = await WebAssembly.instantiateStreaming(
  fetch('module.wasm')
)
const result = wasmModule.instance.exports.add(1, 2)

// Node.js native addons (N-API)
// Written in C/C++, compiled with node-gyp
const addon = require('./build/Release/myaddon.node')
addon.hello() // Calls native C++ function

// Node.js FFI with ffi-napi
const ffi = require('ffi-napi')
const libm = ffi.Library('libm', {
  ceil: ['double', ['double']],
})
libm.ceil(1.5) // 2

// Child process — call any system command
import { execSync, spawn } from 'child_process'
const output = execSync('ls -la').toString()
// Browser Web APIs
navigator.geolocation.getCurrentPosition(pos => { })
const stream = await navigator.mediaDevices.getUserMedia({ video: true })

// postMessage — cross-origin / worker communication
worker.postMessage({ type: 'compute', data })
window.parent.postMessage('done', 'https://parent.com')

// JSON — universal data interchange
const data = JSON.parse(jsonString)
const json = JSON.stringify(data)

Packaging & Distribution

Publish libraries to npm. Distribute apps as Docker containers, serverless functions, or static sites.

# Publish a library to npm
npm login
npm publish               # Public package
npm publish --access public  # Scoped package (@org/pkg)

# package.json essentials
{
  "name": "my-lib",
  "version": "1.0.0",
  "main": "dist/index.cjs",
  "module": "dist/index.mjs",
  "types": "dist/index.d.ts",
  "exports": {
    ".": {
      "import": "./dist/index.mjs",
      "require": "./dist/index.cjs"
    }
  },
  "files": ["dist"]
}

# Build before publishing
npm run build
npm pack --dry-run  # Preview what gets published
# CLI distribution
# Add "bin" field to package.json
# "bin": { "mycli": "./dist/cli.js" }
npm publish
# Users: npx mycli or npm install -g mycli

# Docker
FROM node:22-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --production
COPY dist/ ./dist/
CMD ["node", "dist/index.js"]

# Static site deployment
# Vercel, Netlify, Cloudflare Pages — auto-deploy from Git
# npx vercel deploy