You need Node installed, and to know how to run a
.js file. If node --version in a terminal
prints a version number, you are ready. If it does not — or if you
have never opened a terminal — do
Getting Started with
JavaScript first; it installs Node and runs your first program in about
fifteen minutes. Nothing else is needed.
Arrays
An array is an ordered collection of values. Arrays in JavaScript can hold any type of data — strings, numbers, booleans, objects, even other arrays. They are zero-indexed, meaning the first element is at position 0.
// Creating arrays
const fruits = ["apple", "banana", "cherry"];
const numbers = [1, 2, 3, 4, 5];
const mixed = ["hello", 42, true, null, [1, 2]];
const empty = [];
// Accessing elements (0-indexed)
console.log(fruits[0]); // "apple"
console.log(fruits[1]); // "banana"
console.log(fruits[2]); // "cherry"
console.log(fruits[-1]); // undefined (use .at(-1) instead)
console.log(fruits.at(-1)); // "cherry" (last element)
// Array length
console.log(fruits.length); // 3
// Modifying elements
fruits[1] = "blueberry";
console.log(fruits); // ["apple", "blueberry", "cherry"]
// Checking if something is an array
console.log(Array.isArray(fruits)); // true
console.log(Array.isArray("hello")); // false
Array Methods
Adding and Removing Elements
const colors = ["red", "green", "blue"];
// push — add to the end
colors.push("yellow");
console.log(colors); // ["red", "green", "blue", "yellow"]
// pop — remove from the end
const last = colors.pop();
console.log(last); // "yellow"
console.log(colors); // ["red", "green", "blue"]
// unshift — add to the beginning
colors.unshift("purple");
console.log(colors); // ["purple", "red", "green", "blue"]
// shift — remove from the beginning
const first = colors.shift();
console.log(first); // "purple"
console.log(colors); // ["red", "green", "blue"]
// splice — add/remove at any position
// splice(startIndex, deleteCount, ...itemsToAdd)
colors.splice(1, 0, "orange"); // insert "orange" at index 1
console.log(colors); // ["red", "orange", "green", "blue"]
colors.splice(2, 1); // remove 1 element at index 2
console.log(colors); // ["red", "orange", "blue"]
colors.splice(1, 1, "yellow", "pink"); // replace 1 element with 2
console.log(colors); // ["red", "yellow", "pink", "blue"]
map, filter, and reduce
These three methods are the backbone of data transformation in JavaScript. They do not modify the original array — they return new values. Learning them well will make you dramatically more productive. You will encounter them in virtually every JavaScript codebase.
const numbers = [1, 2, 3, 4, 5];
// map — transform each element, return new array
const doubled = numbers.map(n => n * 2);
console.log(doubled); // [2, 4, 6, 8, 10]
console.log(numbers); // [1, 2, 3, 4, 5] — original unchanged
const names = ["alice", "bob", "charlie"];
const capitalized = names.map(name => name.charAt(0).toUpperCase() + name.slice(1));
console.log(capitalized); // ["Alice", "Bob", "Charlie"]
// filter — keep elements that pass a test, return new array
const evens = numbers.filter(n => n % 2 === 0);
console.log(evens); // [2, 4]
const longNames = names.filter(name => name.length > 3);
console.log(longNames); // ["alice", "charlie"]
// reduce — combine all elements into a single value
const sum = numbers.reduce((accumulator, current) => accumulator + current, 0);
console.log(sum); // 15
// reduce to find the maximum
const max = numbers.reduce((max, n) => n > max ? n : max, numbers[0]);
console.log(max); // 5
// Chaining methods together
const result = numbers
.filter(n => n % 2 !== 0) // [1, 3, 5]
.map(n => n * 10) // [10, 30, 50]
.reduce((sum, n) => sum + n, 0); // 90
console.log(result); // 90
find, includes, and indexOf
const users = [
{ name: "Alice", age: 25 },
{ name: "Bob", age: 30 },
{ name: "Charlie", age: 35 }
];
// find — get the first element that matches
const bob = users.find(user => user.name === "Bob");
console.log(bob); // { name: "Bob", age: 30 }
// findIndex — get the index of the first match
const bobIndex = users.findIndex(user => user.name === "Bob");
console.log(bobIndex); // 1
// includes — check if a value exists (simple values only)
const fruits = ["apple", "banana", "cherry"];
console.log(fruits.includes("banana")); // true
console.log(fruits.includes("grape")); // false
// indexOf — get the index of a value (-1 if not found)
console.log(fruits.indexOf("cherry")); // 2
console.log(fruits.indexOf("grape")); // -1
// some — does at least one element pass the test?
const hasAdult = users.some(user => user.age >= 18);
console.log(hasAdult); // true
// every — do ALL elements pass the test?
const allAdults = users.every(user => user.age >= 18);
console.log(allAdults); // true
Other Useful Array Methods
// sort — sorts in place (mutates the array)
const nums = [3, 1, 4, 1, 5, 9];
nums.sort((a, b) => a - b); // ascending
console.log(nums); // [1, 1, 3, 4, 5, 9]
nums.sort((a, b) => b - a); // descending
console.log(nums); // [9, 5, 4, 3, 1, 1]
// reverse — reverses in place
const letters = ["a", "b", "c"];
letters.reverse();
console.log(letters); // ["c", "b", "a"]
// join — combine into a string
const words = ["Hello", "World"];
console.log(words.join(" ")); // "Hello World"
console.log(words.join("-")); // "Hello-World"
// slice — extract a portion (does NOT mutate)
const colors = ["red", "orange", "yellow", "green", "blue"];
console.log(colors.slice(1, 3)); // ["orange", "yellow"]
console.log(colors.slice(-2)); // ["green", "blue"]
// flat — flatten nested arrays
const nested = [1, [2, 3], [4, [5, 6]]];
console.log(nested.flat()); // [1, 2, 3, 4, [5, 6]]
console.log(nested.flat(2)); // [1, 2, 3, 4, 5, 6] (depth 2)
Destructuring Arrays
Destructuring lets you unpack values from arrays into individual variables in a single statement:
// Basic array destructuring
const colors = ["red", "green", "blue"];
const [first, second, third] = colors;
console.log(first); // "red"
console.log(second); // "green"
console.log(third); // "blue"
// Skip elements with empty slots
const [, , thirdOnly] = colors;
console.log(thirdOnly); // "blue"
// Default values
const [a, b, c, d = "yellow"] = colors;
console.log(d); // "yellow" (default, since colors[3] is undefined)
// Rest pattern — collect remaining elements
const [head, ...tail] = [1, 2, 3, 4, 5];
console.log(head); // 1
console.log(tail); // [2, 3, 4, 5]
// Swapping variables (no temp variable needed!)
let x = 1;
let y = 2;
[x, y] = [y, x];
console.log(x); // 2
console.log(y); // 1
// Destructuring function return values
function getCoordinates() {
return [40.7128, -74.0060];
}
const [lat, lng] = getCoordinates();
console.log(`Latitude: ${lat}, Longitude: ${lng}`);
Objects
Objects are collections of key-value pairs. They are JavaScript's most versatile data structure — similar to Python's dictionaries but with additional capabilities.
// Creating objects
const user = {
name: "Alice",
age: 25,
email: "alice@example.com",
isAdmin: false
};
// Accessing properties — dot notation
console.log(user.name); // "Alice"
console.log(user.age); // 25
// Accessing properties — bracket notation
console.log(user["email"]); // "alice@example.com"
// Bracket notation is required for:
const key = "name";
console.log(user[key]); // "Alice" (dynamic key)
// Keys with special characters
const obj = { "full-name": "Alice Smith", "2fast": true };
console.log(obj["full-name"]); // "Alice Smith"
// Modifying properties
user.age = 26;
user.phone = "+1234567890"; // add new property
console.log(user);
// Removing properties
delete user.phone;
console.log(user.phone); // undefined
// Check if a property exists
console.log("name" in user); // true
console.log("phone" in user); // false
console.log(user.hasOwnProperty("age")); // true
Shorthand Property Names
// When variable name matches the key, you can shorten it
const name = "Alice";
const age = 25;
const city = "London";
// Long form
const userLong = { name: name, age: age, city: city };
// Shorthand (same result)
const userShort = { name, age, city };
console.log(userShort); // { name: "Alice", age: 25, city: "London" }
Iterating Over Objects
const user = { name: "Alice", age: 25, city: "London" };
// Object.keys() — array of keys
console.log(Object.keys(user)); // ["name", "age", "city"]
// Object.values() — array of values
console.log(Object.values(user)); // ["Alice", 25, "London"]
// Object.entries() — array of [key, value] pairs
console.log(Object.entries(user));
// [["name", "Alice"], ["age", 25], ["city", "London"]]
// Looping with for...in
for (const key in user) {
console.log(`${key}: ${user[key]}`);
}
// Looping with Object.entries() and for...of
for (const [key, value] of Object.entries(user)) {
console.log(`${key}: ${value}`);
}
Object Methods
Objects can contain functions as values. When a function is a property of an object, it is called a method:
const calculator = {
// Method shorthand (ES6)
add(a, b) {
return a + b;
},
subtract(a, b) {
return a - b;
},
// Method using 'this' to access own properties
history: [],
calculate(a, op, b) {
let result;
if (op === "+") result = this.add(a, b);
else if (op === "-") result = this.subtract(a, b);
this.history.push(`${a} ${op} ${b} = ${result}`);
return result;
}
};
console.log(calculator.calculate(5, "+", 3)); // 8
console.log(calculator.calculate(10, "-", 4)); // 6
console.log(calculator.history);
// ["5 + 3 = 8", "10 - 4 = 6"]
// Object.assign — merge objects
const defaults = { theme: "dark", lang: "en", notifications: true };
const userPrefs = { theme: "light", lang: "fr" };
const settings = Object.assign({}, defaults, userPrefs);
console.log(settings);
// { theme: "light", lang: "fr", notifications: true }
// Object.freeze — make an object immutable
const config = Object.freeze({ apiUrl: "https://api.example.com", timeout: 5000 });
config.apiUrl = "changed"; // silently fails (or throws in strict mode)
console.log(config.apiUrl); // "https://api.example.com" — unchanged
Destructuring Objects
Object destructuring extracts properties into variables. It matches by property name, not position (unlike array destructuring):
const user = {
name: "Alice",
age: 25,
email: "alice@example.com",
address: {
city: "London",
country: "UK"
}
};
// Basic destructuring
const { name, age, email } = user;
console.log(name); // "Alice"
console.log(age); // 25
console.log(email); // "alice@example.com"
// Rename variables
const { name: userName, age: userAge } = user;
console.log(userName); // "Alice"
console.log(userAge); // 25
// Default values
const { name: n, role = "viewer" } = user;
console.log(n); // "Alice"
console.log(role); // "viewer" (default, since user.role is undefined)
// Nested destructuring
const { address: { city, country } } = user;
console.log(city); // "London"
console.log(country); // "UK"
// Destructuring in function parameters
function greetUser({ name, age }) {
console.log(`Hello ${name}, you are ${age} years old.`);
}
greetUser(user); // "Hello Alice, you are 25 years old."
// With defaults in parameters
function createProfile({ name, role = "user", active = true } = {}) {
return { name, role, active };
}
console.log(createProfile({ name: "Bob" }));
// { name: "Bob", role: "user", active: true }
Spread and Rest Operators
The ... syntax serves two purposes: spread
(expanding) and rest (collecting). Which one it is depends
on context.
Spread — Expanding Arrays
// Copy an array (shallow copy)
const original = [1, 2, 3];
const copy = [...original];
copy.push(4);
console.log(original); // [1, 2, 3] — unchanged
console.log(copy); // [1, 2, 3, 4]
// Merge arrays
const front = [1, 2, 3];
const back = [4, 5, 6];
const combined = [...front, ...back];
console.log(combined); // [1, 2, 3, 4, 5, 6]
// Insert elements
const middle = [1, ...front, 99, ...back, 100];
console.log(middle); // [1, 1, 2, 3, 99, 4, 5, 6, 100]
// Spread a string into characters
const chars = [..."Hello"];
console.log(chars); // ["H", "e", "l", "l", "o"]
// Pass array elements as function arguments
const numbers = [5, 2, 8, 1, 9];
console.log(Math.max(...numbers)); // 9
Spread — Expanding Objects
// Copy an object (shallow copy)
const user = { name: "Alice", age: 25 };
const userCopy = { ...user };
userCopy.age = 26;
console.log(user.age); // 25 — unchanged
console.log(userCopy.age); // 26
// Merge objects (later properties win)
const defaults = { theme: "dark", lang: "en", debug: false };
const overrides = { theme: "light", debug: true };
const config = { ...defaults, ...overrides };
console.log(config);
// { theme: "light", lang: "en", debug: true }
// Add/override properties
const updatedUser = { ...user, age: 26, email: "alice@example.com" };
console.log(updatedUser);
// { name: "Alice", age: 26, email: "alice@example.com" }
Rest — Collecting Remaining Elements
// Rest in array destructuring
const [first, second, ...rest] = [1, 2, 3, 4, 5];
console.log(first); // 1
console.log(second); // 2
console.log(rest); // [3, 4, 5]
// Rest in object destructuring
const { name, ...otherProps } = { name: "Alice", age: 25, city: "London" };
console.log(name); // "Alice"
console.log(otherProps); // { age: 25, city: "London" }
// Rest in function parameters
function logAll(first, ...others) {
console.log(`First: ${first}`);
console.log(`Others: ${others}`);
}
logAll("a", "b", "c", "d");
// "First: a"
// "Others: b,c,d"
JSON
JSON (JavaScript Object Notation) is a text format for storing and exchanging data. It looks almost identical to JavaScript objects, but with stricter rules: keys must be double-quoted strings, and values cannot be functions, undefined, or symbols.
// JavaScript object
const user = {
name: "Alice",
age: 25,
hobbies: ["reading", "coding"],
address: {
city: "London",
country: "UK"
}
};
// Convert object to JSON string
const jsonString = JSON.stringify(user);
console.log(jsonString);
// '{"name":"Alice","age":25,"hobbies":["reading","coding"],"address":{"city":"London","country":"UK"}}'
// Pretty-print with indentation
const pretty = JSON.stringify(user, null, 2);
console.log(pretty);
// {
// "name": "Alice",
// "age": 25,
// "hobbies": [
// "reading",
// "coding"
// ],
// "address": {
// "city": "London",
// "country": "UK"
// }
// }
// Parse JSON string back to object
const parsed = JSON.parse(jsonString);
console.log(parsed.name); // "Alice"
console.log(parsed.hobbies[0]); // "reading"
console.log(parsed.address.city); // "London"
Working with JSON and APIs
// JSON is the standard format for web APIs
// Here's a typical pattern for fetching JSON data:
// fetch("https://api.example.com/users")
// .then(response => response.json())
// .then(data => {
// console.log(data);
// });
// Deep clone an object using JSON (simple but effective)
const original = { a: 1, b: { c: 2 } };
const deepCopy = JSON.parse(JSON.stringify(original));
deepCopy.b.c = 99;
console.log(original.b.c); // 2 — original unaffected
// JSON limitations — these values are lost or converted:
const problematic = {
func: function() {}, // lost (functions not supported)
undef: undefined, // lost
date: new Date(), // converted to string
regex: /test/, // converted to {}
num: 42 // works fine
};
const roundTrip = JSON.parse(JSON.stringify(problematic));
console.log(roundTrip);
// { date: "2026-03-04T...", regex: {}, num: 42 }
// func and undef are gone
Now Do It Yourself: Five Steps
One small shopping list, handled five ways: reading an array, transforming the whole of it at once, describing a single item as an object, changing a copy without wrecking the original, and turning the result into text that a file or an API can carry. Every output below is exactly what Node printed.
Go: open a terminal, cd to a folder you can write in, and create a file called shop.js.
Do: type these six lines and run node shop.js.
const prices = [12.5, 4, 30, 7.25];
console.log(prices.length);
console.log(prices[0]);
console.log(prices[3]);
console.log(prices[4]);
console.log(prices.at(-1));
You should see: 4, 12.5, 7.25, undefined, 7.25. Four values, so the last one sits at position 3 — counting starts at 0, and the last position is always length - 1. Notice that asking for position 4 is not an error: JavaScript hands back undefined, which is why an off-by-one usually surfaces much later as a strange result rather than a crash.
If not: ReferenceError: prices is not defined means the file you ran is not the file you edited — save it, and check that node shop.js names the same file you are typing into. If you tried prices[-1] hoping for the last item, undefined is the correct answer: negative positions only work through .at(-1).
Go: same file, replace the contents.
Do: type these seven lines and run it.
const prices = [12.5, 4, 30, 7.25];
const withTax = prices.map(p => p * 1.2);
console.log(withTax);
const big = prices.filter(p => p >= 10);
console.log(big);
const total = prices.reduce((sum, p) => sum + p, 0);
console.log(total);
You should see: [ 15, 4.8, 36, 8.7 ], then [ 12.5, 30 ], then 53.75. Three jobs, three methods: map returns a new array of the same length, filter a shorter one, reduce a single value. None of them touches prices — that is the whole point of using them instead of a loop that edits as it goes.
If not: if the total prints 0123 instead of a number, your list holds text rather than numbers, and + is joining strings instead of adding them. Quotation marks are the difference: "12.5" is text, 12.5 is a number. If you get undefined, you left the 0 out of reduce’s second argument on a list that could be empty.
Go: same file, replace the contents.
Do: type these eight lines and run it.
const item = { name: "keyboard", price: 30, inStock: true };
console.log(item.name);
console.log(item["price"]);
console.log(item.colour);
console.log("item is " + item);
for (const [key, value] of Object.entries(item)) {
console.log(key, "=", value);
}
You should see: keyboard, 30, undefined, item is [object Object], then three lines — name = keyboard, price = 30, inStock = true. An array is things in order; an object is one thing with named parts. Two things worth keeping: a key that does not exist is undefined rather than an error, and gluing an object onto a string with + gives you the useless [object Object]. Pass it as a separate argument instead — console.log("item is", item) — and you get the real contents.
If not: SyntaxError: Invalid shorthand property initializer means you wrote name = "keyboard" inside the braces. Inside an object it is a colon, not an equals sign: name: "keyboard".
Go: same file, replace the contents.
Do: type these six lines and run it.
const item = { name: "keyboard", price: 30, inStock: true };
const { name, price } = item;
console.log(name, price);
const discounted = { ...item, price: 24 };
console.log(discounted);
console.log(item);
You should see: keyboard 30, then { name: 'keyboard', price: 24, inStock: true }, then { name: 'keyboard', price: 30, inStock: true }. The braces on the left of = pull named parts out into their own variables. The three dots copy every field into a new object, and because price: 24 is written after them, it wins — so you end up with a changed copy and an untouched original.
If not: if discounted still shows price: 30, you wrote { price: 24, ...item }. Later keys overwrite earlier ones, so the spread lands on top of your change and undoes it. Put your override last, every time.
Go: same file, replace the contents.
Do: type these seven lines and run it.
const item = { name: "keyboard", price: 30, tags: ["usb", "wired"] };
const text = JSON.stringify(item);
console.log(text);
console.log(typeof text);
const back = JSON.parse(text);
console.log(back.tags[1]);
console.log(typeof back);
You should see: {"name":"keyboard","price":30,"tags":["usb","wired"]}, then string, then wired, then object. That round trip is how objects travel: a file, a network request and a database column all carry text, never live objects. stringify flattens an object into text; parse builds a fresh object back out of it.
If not: SyntaxError: "[object Object]" is not valid JSON means you handed the object itself to JSON.parse instead of the string. The two go in opposite directions, and swapping them produces exactly that message.
Without scrolling up: you copy an order with const copy = { ...order };
and then run copy.lines.push("c"). Why does order.lines
change as well? Answer: the three dots copy one level deep. The value stored
under lines is a reference to an array, so the copy points at the very
same array. To copy the inside too, rebuild it:
{ ...order, lines: [...order.lines] }.
Now do it without the page: starting from the four prices in
step 2, print a single JSON string containing only the prices above 10, with tax
added. You already have all three pieces — filter, then
map, then JSON.stringify, chained in that order. The
answer is [15,36].
Summary
- Arrays are ordered, zero-indexed collections:
["a", "b", "c"] - push/pop add/remove from end; unshift/shift add/remove from start
- map transforms, filter selects, reduce combines — learn these well
- find/includes/indexOf — search for elements in arrays
- Array destructuring:
const [a, b] = array - Objects are key-value pairs:
{ name: "Alice", age: 25 } - Access with dot notation (
obj.key) or brackets (obj["key"]) - Object destructuring:
const { name, age } = obj - Spread (
...) expands arrays/objects; rest (...) collects remaining items - JSON.stringify() and JSON.parse() convert between objects and JSON strings
You now have a solid grasp of JavaScript's most important data structures. With variables, control flow, functions, arrays, and objects under your belt, you have the foundation to build real applications and dive into more advanced topics like the DOM, async programming, and frameworks.