Phase 1 · Node.js FoundationsModule 2~46 min read

JavaScript Essentials for Node.js

Build the modern JavaScript foundation needed for Node.js with values, functions, objects, collections, destructuring, and clean control flow.

What you'll learn

Node.js programs are JavaScript programs. This focused language refresher gives you the values, functions, collections, and data-transformation habits required for every backend lesson that follows.

By the end of this lesson, you'll be able to:

  • Choose const and let deliberately and recognize primitive versus reference values
  • Write small functions with defaults, rest parameters, and predictable returns
  • Transform arrays with map, filter, find, and reduce
  • Read and construct objects with destructuring, spread, and optional chaining

Core mental model

Node.js becomes easier when you separate the JavaScript language from the runtime and the operating-system capabilities it exposes. Use this table as a decision guide.

ConceptWhat it meansDecision rule
Value vs referencePrimitives copy values; objects and arrays share referencesCopy shared structures before changing them when callers expect immutability
Pure functionOutput depends on inputs without hidden mutationKeep business calculations pure; isolate files, logs, and network calls at boundaries
Collection pipelineA sequence of focused transformationsUse map/filter/reduce when each step is clearer than one stateful loop
Defensive accessOptional chaining and nullish defaults handle absent dataValidate required input; default only genuinely optional input

Professional workflow

Build and verify Node.js programs from the terminal in small, observable steps.

  1. Write down the input and output shape before implementing a transformation.
  2. Validate required values at the boundary and convert them once.
  3. Use const by default; introduce let only for intentional reassignment.
  4. Break multi-step behavior into named functions with one responsibility each.
  5. Exercise empty, missing, zero, false, and malformed values before refactoring.

Keep the feedback loop short

Run the smallest useful command after every meaningful change. Read the complete error message before editing again, and keep inputs and outputs visible while you learn.

Guided code lab

Transform server-style records without mutation

The pipeline validates active records, calculates totals, and creates new response objects while leaving the source unchanged.

orders.js
const orders = [
  { id: 1, active: true, price: 12, quantity: 2 },
  { id: 2, active: false, price: 8, quantity: 4 },
  { id: 3, active: true, price: 5, quantity: 3 },
];

const summaries = orders
  .filter((order) => order.active)
  .map(({ id, price, quantity }) => ({ id, total: price * quantity }));

console.log(summaries);

Normalize optional configuration

Destructuring makes expected fields visible. Nullish coalescing preserves meaningful false and zero values while supplying defaults for null or undefined.

config.js
function normalizeConfig(input = {}) {
  const {
    port = 3000,
    logging = true,
    database: { host = "localhost" } = {},
  } = input;

  return { port: Number(port), logging: logging ?? true, host };
}

console.log(normalizeConfig({ port: "8080", logging: false }));

Separate validation from calculation

Each function has a clear contract, making failures easier to test and reuse later in an API or CLI.

invoice.js
function assertLine(line) {
  if (!Number.isFinite(line.price) || line.price < 0) {
    throw new TypeError("price must be a non-negative number");
  }
  if (!Number.isInteger(line.quantity) || line.quantity < 1) {
    throw new TypeError("quantity must be a positive integer");
  }
}

function invoiceTotal(lines, taxRate = 0) {
  lines.forEach(assertLine);
  const subtotal = lines.reduce(
    (sum, line) => sum + line.price * line.quantity,
    0,
  );
  return subtotal * (1 + taxRate);
}

console.log(invoiceTotal([{ price: 20, quantity: 2 }], 0.1));

Production practice

Validate once

Convert untrusted strings and validate required fields at the program boundary; keep the inner model consistent.

Avoid hidden mutation

Return new objects from transformations unless the function clearly documents in-place behavior.

Prefer clarity

A direct loop is better than a clever pipeline when it makes state, errors, or early exits easier to follow.

Common failure mode

Using || for every default silently replaces valid values such as 0, false, and the empty string. Use ?? when only null or undefined should trigger the fallback.

Independent workshop

Build an inventory report that validates raw product records, keeps only available items, computes stock value, and returns a summary object.

Your finished workshop must include:

  • Separate normalize, validate, and summarize functions
  • No mutation of the input array or its objects
  • Useful errors for invalid price and quantity
  • Examples covering empty inventory and zero stock

Definition of done

Run the happy path and at least two edge cases, keep responsibilities separated, and add a short README explaining how to run the program.

Recap & quick check

Key takeaways

  • Node.js uses ordinary modern JavaScript
  • Pure functions keep core logic testable
  • Array methods express focused transformations
  • Destructuring documents consumed shapes
  • Nullish defaults preserve false and zero

Quick check

1. Which declaration should be the default for a binding that will not be reassigned?

2. Which method creates one output element for every input element?

3. Why use ?? instead of || for a numeric configuration value?

4. What does object spread create?

Next: Inside the Node.js Runtime