Free Handbook · Runs in your browser

Data Types

Numbers and Math, strings and their methods, arrays and the methods you use daily, objects as the workhorse, Map and Set, JSON — with the missing-property TypeError, not-a-number and reference-copy bugs each one hands you, and a guide to choosing.

0 / 111 lessons🔥 0 day streak
ShareXLinkedIn

Module 03 · what you'll be able to do

  • Use Number, Math and know where floats lie to you
  • Slice, search, split, join and format strings
  • Build, index, mutate and transform arrays; know which methods mutate
  • Use objects as records and dictionaries; copy them correctly
  • Reach for Map and Set when they beat objects and arrays
  • Serialise with JSON.stringify and parse with JSON.parse safely
01

Numbers and Math

javascriptEdit it. ⌘/Ctrl + Enter runs.
You should see
0.30000000000000004 false
true
0.30 0.3
1998.9999999999998 1999
3 -2 -3 3 -2
9 2 4 3.1416 1024
true true
true false false
8 1000 ff 11111111
1,234,567.891 26%
Your turn
Compute compound interest: 1000 at 5% for 10 years, to 2 decimals. Then do it in integer cents and compare.
Error you will hit

NaN: the number that is not a number

javascript
const price = Number("free")
const total = price * 3
console.log(total, total === NaN, typeof total)
NaN false number
Why the engine said that

Any arithmetic on a non-numeric string, undefined, or an invalid operation (0 / 0, Math.sqrt(-1)) gives NaN. It is contagious — every operation on it stays NaN — and it is the only value not equal to itself, so === NaN is always false.

The fix

Check with Number.isNaN(x) (not the global isNaN, which coerces). Validate inputs at the edge: const n = Number(input); if (Number.isNaN(n)) throw ….

javascript
const price = Number("free")
if (Number.isNaN(price)) {
  console.log("not a price")
}
Never store money in a float
19.99 * 100 is 1998.9999999999998. Work in integer cents, or use a decimal library. Interviewers ask about this in every language.
02

Strings

Strings are immutable: every method returns a new string and the original never changes. That is why s.toUpperCase() on its own does nothing visible — keep the result. Indexing with [i] and .length work like arrays, but you cannot assign to s[0].

javascriptEdit it. ⌘/Ctrl + Enter runs.
You should see
H d 12 Hello World World
HELLO, WORLD hello, world
7 -1 true true false
Hello, JS a+b+c
padded| 005 ababab
[ 'Hello', 'World' ] [ '2026', '09', '20' ] 12
data engineering dlroW ,olleH
72 B true false
Ada has 3 items
true 1 [ 'a', 'b', 'C' ]
Your turn
Check whether "A man, a plan, a canal: Panama" is a palindrome — lowercase it, keep only letters with a regex replace(/[^a-z]/g, ""), compare with its reverse.
Error you will hit

Assigning to a string index does nothing

javascript
"use strict"
let word = "cat"
word[0] = "b"
console.log(word)
Uncaught TypeError: Cannot assign to read only property '0' of string 'cat'
    at your code:3
Why the engine said that

Strings cannot be changed in place. In sloppy mode the assignment silently does nothing and prints cat; in strict mode (modules, classes, this example) it throws.

The fix

Build a new string and rebind the name.

javascript
let word = "cat"
word = "b" + word.slice(1)
console.log(word)   // bat
Immutable
Cannot be changed after creation. All primitives are immutable; objects and arrays are mutable.
slice(start, end)
End exclusive, negatives from the end, never throws — clips. Works on strings and arrays. (substring and substr are older; use slice.)
03

Arrays

An array is an ordered list of anything, and the container you reach for by default. The key thing to learn is which methods mutate the array (push, pop, shift, unshift, splice, sort, reverse) and which return a new one (map, filter, slice, concat, toSorted). Mixing them up is the number-one array bug.

javascriptEdit it. ⌘/Ctrl + Enter runs.
You should see
[ 7, 4, 1, 3, 9 ] 5
9 7 [ 4, 1, 3 ]
[ 4, 8, 8, 3 ]
1 true 3 [ 8, 8 ]
[ 1, 10, 9 ] [ 1, 9, 10 ] [ 10, 9, 1 ]
[ 1, 9, 10 ]
[ 10, 9, 1 ]
[ 0, 1, 4, 9 ] [ 0, 0, 0 ] [ 'a', 'b', 'c' ]
[ 1, 2, 3, 4 ] [ 1, 2, 3, 4 ]
2 1 [ 3, 4 ]
[ 1, 2, 3, 4 ] [ 1, 2, 3 ]
Your turn
Given scores = [88, 92, 79, 93, 85], print the top two and the average to one decimal — without mutating scores.
Error you will hit

[10, 9, 1].sort() gives [1, 10, 9]

javascript
const prices = [10, 9, 1, 100]
prices.sort()
console.log(prices)
[ 1, 10, 100, 9 ]
Why the engine said that

No error, wrong order. The default comparison converts elements to strings and compares them character by character: "10" < "9" because "1" < "9".

The fix

Always pass a comparator for numbers: (a, b) => a - b ascending, b - a descending. For objects: (a, b) => a.age - b.age; for strings, a.localeCompare(b).

javascript
const prices = [10, 9, 1, 100]
prices.sort((a, b) => a - b)
console.log(prices)   // [ 1, 9, 10, 100 ]
The 2023 to… methods are the non-mutating twins of sort/reverse/splice. Prefer them in React state and anywhere the original must survive.
Mutates the arrayReturns a new array
push pop shift unshiftmap filter slice concat flat
splice sort reverse filltoSorted toReversed toSpliced with
[...arr] Array.from(arr)
04

Objects

An object is a collection of key → value pairs. Keys are strings (or symbols); values are anything. Objects play two roles: a record with known fields (user.name) and a dictionary with dynamic keys (counts[word]). For the second role, Map (next lesson) is often better. Objects are compared and copied by reference — the single most important thing to understand about them.

javascriptEdit it. ⌘/Ctrl + Enter runs.
You should see
Ada London admin
{ name: 'Ada', age: 37, 'home city': 'London', email: '[email protected]' }
true undefined n/a undefined
ops function hi Grace
name Ada
age 37
home city London
email [email protected]
4
{ a: 3, b: 2, c: 1 }
2 true false
{ x: 2, y: 3 } 1
Ada 37 dflt
Your turn
Write invert(obj) that swaps keys and values: {a: 1, b: 2}{1: "a", 2: "b"}. Use Object.entries and Object.fromEntries.
Error you will hit

TypeError: Cannot read properties of undefined (reading 'city')

javascript
const user = { name: "Ada" }
console.log(user.address.city)
Uncaught TypeError: Cannot read properties of undefined (reading 'city')
    at your code:2
Why the engine said that

The most common error in all of JavaScript. user.address is undefined (the key does not exist — that is not an error), and then .city on undefined is an error. The message names the property you tried to read (city), so the thing that was undefined is whatever came before it.

The fix

Optional chaining when missing is legitimate: user.address?.city. Otherwise, find out why address was not set — usually data that has not loaded yet (Module 06) or a typo in the key.

javascript
const user = { name: "Ada" }
console.log(user.address?.city ?? "unknown")
Aliasing is the second-most common object bug
b = a makes two names for one object; changing one changes "both". { ...a } copies one level; structuredClone(a) copies everything (not functions). React and Redux depend on you knowing this — you always make a new object rather than mutating the old one.
05

Map and Set

Map is a dictionary done properly: any value can be a key (not just strings), insertion order is kept, .size is a property, and it has no prototype keys to trip over. Set is a collection of unique values with O(1) membership. When the keys are dynamic data — user IDs, words, coordinates — use a Map; when you need "have I seen this", use a Set.

javascriptEdit it. ⌘/Ctrl + Enter runs.
You should see
37 undefined true 3
ada 37
cy 41
[ 'ada', 'cy' ] [ 37, 41 ] { ada: 37, cy: 41 }
start
Set(4) { 1, 2, 3, 4 } true 4
misp
[ 2, 3 ] [ 1, 2, 3, 4 ] [ 1 ]
Map(2) { 'data' => [ 'ada', 'cy' ], 'infra' => [ 'bob' ] }
{ long: [ 'ada', 'bob' ], short: [ 'cy' ] }
Your turn
Write firstRepeat(items) using a Set — return the first value that appears twice, or null. One pass.
ObjectMap
Key typesstring, symbolanything
Orderinsertion (mostly — integer keys first)insertion, always
SizeObject.keys(o).lengthm.size
IterationObject.entriesdirectly iterable
JSONJSON.stringify worksneeds Object.fromEntries first
Use forrecords with known fields; JSONdictionaries keyed by data
06

JSON

JSON is a text format that looks like a JavaScript object literal with stricter rules: double-quoted keys, no trailing commas, no comments, no functions, no undefined. It is how every API talks. JSON.stringify turns a value into that text; JSON.parse turns text back. Parsing untrusted text can throw — wrap it.

javascriptEdit it. ⌘/Ctrl + Enter runs.
You should see
{"name":"Ada","age":36,"tags":["admin"],"nested":{"ok":true},"nothing":null}
{
  "name": "Ada",
  "age": 36,
  "tags": [
    "admin"
  ],
  "nested": {
    "ok": true
  },
  "nothing": null
}
{"name":"Ada","age":36}
Ada true false
string 1970
{ a: 1 } {} 42
{ a: [ 1, { b: 2 } ] }
Error you will hit

SyntaxError: Unexpected token '}', "{"a": }" is not valid JSON

javascript
const data = JSON.parse('{"a": }')
Uncaught SyntaxError: Unexpected token '}', "{"a": }" is not valid JSON
    at JSON.parse (<anonymous>)
    at your code:1
Why the engine said that

The text is not JSON. In real life this means the API returned an HTML error page, an empty body, or a string with a trailing comma. JSON.parse throws rather than guessing.

The fix

Log the raw text before parsing when debugging. In production, catch the error and treat it as a failed request. Never build JSON by string concatenation — use JSON.stringify.

07

Choosing the right type

You need…UseWhy
An ordered list you loop overArrayIndex, iteration, map/filter/reduce
A record with known fieldsObject (or a class, Module 08)Dot access reads like English; JSON-ready
A dictionary keyed by dataMapAny key type, .size, safe iteration order
Uniqueness or membershipSetO(1) has(), dedupe with spread
A fixed pair or tripleArray + destructuringconst [lat, lng] = point
TextString + template literalImmutable, rich methods
MoneyInteger centsFloats cannot represent 0.1
Very large integersBigIntBeyond 2⁵³
Quick check

You have 1,000,000 user IDs and need to check 50,000 incoming IDs against them. Best structure for the known IDs?

Mid-levelWhen would you use a Map instead of a plain object?

When keys are dynamic data rather than fixed field names: keys can be any type (objects, numbers without string coercion), iteration order is guaranteed, size is O(1), there are no inherited keys like constructor to collide with, and frequent add/delete performs better. Plain objects stay for records and for anything that must become JSON.

Finish the JavaScript handbook, then get hired

Sit the exam for your certificate, run your resume through the ATS checker, and see the jobs that ask for exactly this.

Check my resume
Found this course useful? Share it.
ShareXLinkedIn

Comments

0

Join the conversation. Sign in to leave a comment — we'd love to hear your thoughts.