Chapter 6 Β· Expressions & Built-in Data

Numbers, Strings, Dates & Intl

The everyday data: numbers that are always floats (plus BigInt), strings made of UTF-16 code units, template literals and tags, the famously awkward Date and its replacement Temporal, and the Intl APIs that format all of it for any language.

You will learn

  • Number precision, safe integers, Number.EPSILON, parsing and rounding pitfalls.
  • Strings as UTF-16: length vs characters, and the modern string methods.
  • Template literals, tagged templates and String.raw ES2015.
  • Date pitfalls, and the Temporal API as the modern alternative.
  • Locale-aware formatting with Intl: currency, dates, plurals, lists, sorting.

Numbers

Every number is a 64-bit IEEE-754 float, the same as Java's double. Integers are exact only up to Number.MAX_SAFE_INTEGER (253 βˆ’ 1). Beyond that, use BigInt.

πŸ’‘ Money: store integer cents (1299), not 12.99, and format only for display. That avoids float drift in totals, the same advice as Java's BigDecimal.

Converting strings to numbers

ExpressionResultWhy
Number("12px")NaNthe whole string must be numeric
parseInt("12px")12parses a prefix, stops at the first bad character
parseFloat("3.14abc")3.14same, for decimals
Number("") / Number(" 42 ")0 / 42whitespace is trimmed, and an empty string is 0 ⚠️
parseInt("ff", 16)255always pass the radix
isNaN("abc") vs Number.isNaN("abc")true vs falsethe global one converts first; Number.isNaN ES2015 doesn't

Rounding

BigInt ES2020

BigInt division truncates. You can't mix BigInt and Number in arithmetic (that's a TypeError); convert explicitly with BigInt(n) or Number(b). JSON.stringify can't serialize BigInts.

Strings

A string is an immutable sequence of UTF-16 code units. Most characters are one unit, but emoji and other characters outside the Basic Multilingual Plane are two (a surrogate pair). length counts units, not what a reader sees as characters.

Spreading or for…of iterates by code point. For "what the user sees as one character" (for example πŸ‘πŸ½, which is two code points), use Intl.Segmenter (see the Intl section below).

The modern string methods

MethodExample β†’ resultSince
includes, startsWith, endsWith"invoice.pdf".endsWith(".pdf") β†’ trueES2015
repeat"-".repeat(3) β†’ "---"ES2015
padStart, padEnd"7".padStart(3, "0") β†’ "007"ES2017
trimStart, trimEnd" a ".trimStart() β†’ "a "ES2019
replaceAll"a-b-c".replaceAll("-", "/") β†’ "a/b/c"ES2021
at"Dune".at(-1) β†’ "e"ES2022
isWellFormed, toWellFormeddetect and repair lone surrogatesES2024
slice, split, indexOf, toUpperCase, localeComparethe classicsES5

⚠️ Pitfall: "a-b-c".replace("-", "/") replaces only the first match. Use replaceAll, or a regex with the g flag (Chapter 7).

Template literals ES2015

Backtick strings can span several lines and embed any expression with ${…}.

Tagged templates

A tag is a function placed before a template literal. It receives the literal text pieces and the evaluated values separately, so it can escape, translate or format the values before joining them. Libraries use this for SQL, HTML and CSS.

Dates

Date stores a single moment as milliseconds since 1 January 1970 UTC. It's a leftover from 1995 Java, and it has well-known traps:

TrapExample
Months are 0-based (days are not)new Date(2026, 9, 30) is 30 October
Date-only ISO strings are UTC; date-time strings without a zone are localnew Date("2026-10-30") vs new Date("2026-10-30T00:00")
Dates are mutabled.setDate(d.getDate() + 1) changes d for everyone holding it
Overflow rolls over silentlynew Date(2026, 0, 32) is 1 February
Only local time and UTC; no other time zonesuse Intl to display in another zone

Temporal: the modern replacement

Temporal is a new global API, available in Node 26 and current browsers, that fixes Date's design. It has separate immutable types for different jobs: PlainDate (a calendar date), PlainTime, ZonedDateTime (a moment in a real time zone), Instant and Duration. Months are 1-based, and arithmetic is calendar-aware.

πŸ“ Status: Temporal is new. Check your target browsers or Node version before relying on it, or use the @js-temporal/polyfill package. Date isn't going anywhere, so you'll keep reading it in existing code.

Internationalization with Intl

The Intl namespace formats numbers, dates, lists and plurals, and compares strings, according to a locale such as "de-DE" or "en-IN". Create a formatter once and reuse it; formatters are relatively expensive to build.

⚠️ Pitfall: formatted output may contain special spaces, such as a no-break space before € or a narrow no-break space before AM. Never compare formatted strings in tests against strings you typed by hand; compare the numbers, or use formatToParts().

More examples

1. Summing money safely

2. Masking a card number

3. A receipt line aligned with padEnd/padStart

4. Truncating text by graphemes, not code units

5. Next business day with Temporal

Recap

  • Numbers are doubles: compare floats with a tolerance, store money as integer cents, and use BigInt beyond 253.
  • Prefer Number() plus Number.isNaN; give parseInt a radix. toFixed returns a string.
  • Strings are UTF-16: length counts code units, spread counts code points, and Intl.Segmenter counts what readers see.
  • Template literals interpolate and span lines. Tags receive the literal parts and values separately.
  • Date has 0-based months and mutable objects; Temporal fixes both. Use Intl for all user-facing formatting.

Exercises

Exercise 1 🟒 easy predict the output

Evaluate: Number("42px"), parseInt("42px"), Number(""), parseInt("")

Show solution

NaN, 42, 0, NaN. Number needs the whole string to be numeric, but treats an empty string as 0. parseInt needs at least one digit at the start.

Exercise 2 🟒 easy build it

Format an order number 7 as ORD-00007 using one string method.

Show solution

padStart is a string method, so convert the number first.

Exercise 3 🟒 easy fix the bug

The month shows as November. Fix it.

Show solution

Date months run from 0 to 11. Temporal's month is 1-based, which avoids this bug.

Exercise 4 🟒 easy predict the output

What are "café".length, "🍩".length and [..."🍩🍩"].length?

Show solution

4, 2, 2. "Γ©" written as one code point is one unit; the emoji needs a surrogate pair (2 units) but is one code point.

Exercise 5 🟑 medium build it

Write a tag function upper that upper-cases only the interpolated values: upper`Hi ${"ana"}, your book ${"dune"} shipped` β†’ "Hi ANA, your book DUNE shipped".

Show solution

strings always has one more element than values, which is why the last step adds nothing after the final string.

Exercise 6 🟑 medium explain why

Why does (1.005).toFixed(2) give "1.00" and not "1.01"? How would you round money correctly?

Show solution

1.005 can't be stored exactly. The nearest double is 1.00499999999999989…, which correctly rounds down. Work in integer cents (Math.round(x * 100) at input time), or use a decimal library for exact decimal rounding.

Exercise 7 🟑 medium build it · playground

Create playground/format.js exporting formatPrice(cents, locale, currency), with formatters cached per locale + currency in a Map. Print 1299 cents in en-US/USD, de-DE/EUR and ja-JP/JPY (yen has no minor unit, so 1299 means Β₯1,299).

Show solution

resolvedOptions() reveals how many decimals the currency uses, so the same "minor units" integer works for every currency. Caching avoids rebuilding formatters.

Exercise 8 🟑 medium predict the output

What does ["b", "a", "C", "Γ‘"].sort() return? And with new Intl.Collator("en").compare?

Show solution

['C', 'a', 'b', 'Γ‘'] (by UTF-16 code unit, so uppercase letters come first and accents last), and ['a', 'Γ‘', 'b', 'C'] (the human dictionary order for English).

Exercise 9 πŸ”΄ hard build it

Using Temporal, compute the delivery date for an order placed on "2026-12-23" with 3 business days of shipping, skipping weekends and the holidays 2026-12-25 and 2026-12-26.

Show solution

Walking forward from the 23rd: the 24th (Thursday) counts as day 1; the 25th (Friday) is a holiday; the 26th and 27th are a weekend (the 26th is also a holiday); the 28th (Monday) is day 2 and the 29th is day 3. So delivery is 2026-12-29. dayOfWeek uses ISO numbering: Monday = 1 through Sunday = 7.

Exercise 10 πŸ”΄ hard mini-project Β· playground

Create playground/receipt.js. Given a locale, a currency and line items { title, cents, qty }, print a receipt: aligned columns, an Intl currency for each line and the total, a pluralised item count ("1 item" / "3 items" via Intl.PluralRules), and a date line formatted with Intl.DateTimeFormat in UTC.

Show solution

It uses integer cents, template literals inside padEnd/padStart, three different Intl formatters, and destructured options with defaults.

Official docs