This episode takes functions to a professional level: default parameters for fallback values, the rest parameter for capturing many arguments, and the spread operator for combining arrays and objects. You compose flexible, concise functions in ES6 style.

In episode 4 you already created functions with ordinary parameters. Now it's time to expand those abilities: how a function behaves when an argument isn't passed, how to capture a variable number of arguments, and how to spread an array's or object's contents somewhere else. These three ES6 features — default parameters, the rest parameter, and the spread operator — are used so often in modern JavaScript that they feel indispensable.
All three look similar because they use the ... notation, but their functions are completely different. Distinguishing them clearly will prevent confusion: default parameters fill in empty values, rest gathers many values into one, and spread scatters a collection's contents into many values.
Functions that use all three well become far more concise and safer against unexpected input.
Without default parameters, an argument that isn't passed has the value undefined — and that often makes a function produce strange output. Default parameters set a fallback value used when an argument isn't provided:
function sapa(nama, bahasa = "Indonesia") {
const halo = bahasa === "Inggris" ? "Hello" : "Halo";
return `${halo}, ${nama}!`;
}
console.log(sapa("Arman"));
console.log(sapa("Arman", "Inggris"));function sapa(nama, bahasa = "Indonesia") sets "Indonesia" as the default. Calling sapa("Arman") uses the default, so the result is Halo, Arman!, while sapa("Arman", "Inggris") produces Hello, Arman!. The default value only activates when the argument is undefined.
A default value can be any expression, including the result of calling another function:
function buatId(prefix = "user", nomor = Date.now()) {
return `${prefix}-${nomor}`;
}
console.log(buatId());
console.log(buatId("admin", 7));buatId() produces a timestamp-based ID, while buatId("admin", 7) produces admin-7. Using Date.now() as a default means the function remains useful without arguments — a good pattern for values that either the caller may choose or are determined automatically.
The rest parameter is marked with ... before the parameter name and gathers all extra arguments into an array:
function jumlahkan(...angka) {
let total = 0;
for (const nilai of angka) {
total += nilai;
}
return total;
}
console.log(jumlahkan(1, 2, 3));
console.log(jumlahkan(5, 10, 15, 20));function jumlahkan(...angka) accepts any number of arguments and stores them in the angka array. jumlahkan(1, 2, 3) returns 6, and the four-argument version returns 50. This replaces the old arguments object, whose behavior was confusing.
The rest parameter must be the last parameter, and it can be combined with ordinary parameters:
function daftarBelanja(toko, ...item) {
console.log(`Belanja di: ${toko}`);
return item.join(", ");
}
console.log(daftarBelanja("Toko Bersih", "Beras", "Minyak", "Telur"));function daftarBelanja(toko, ...item) assigns toko as the first argument and item captures the rest. The result is Belanja di: Toko Bersih then Beras, Minyak, Telur. This pattern is very common for functions that need one required argument and the rest optional.
The spread operator (... in front of an array) does the opposite of rest: it scatters a collection's contents into separate values. Its most common use is combining arrays:
const pagi = ["kopi", "telur"];
const siang = ["nasi", "sayur"];
const menu = [...pagi, ...siang];
console.log(menu);
console.log([...menu, "makan malam"]);[...pagi, ...siang] combines two arrays into one without the concat method. Adding elements is also more concise: [...menu, "makan malam"] adds at the end. Spread creates a new array — the original arrays stay unchanged, preventing accidental mutation.
Before spread, copying an array with = only duplicated the reference — changing the copy changed the original array. Spread creates a safe shallow copy:
const asli = [1, 2, 3];
const salinan = [...asli];
salinan.push(4);
console.log(salinan);
console.log(asli);salinan.push(4) only changes salinan, while asli stays [1, 2, 3]. The [...asli] pattern is used everywhere to make a copy before mutating. Remember: this is a shallow copy — objects inside the array still share references, which we'll dig deeper into in episode 22.
Spread also works on objects to combine properties or create copies:
const dasar = { nama: "Arman", role: "Engineer" };
const lengkap = { ...dasar, kota: "Jakarta" };
const duplikat = { ...dasar };
console.log(lengkap);
console.log(duplikat);{ ...dasar, kota: "Jakarta" } combines dasar's properties with new properties. If there's a duplicate key, the later value overwrites it — this is the very common config override pattern: { ...defaultConfig, ...userConfig }.
The three features work together naturally. A classic example: a function that accepts default options and user options:
function buatServer(host = "localhost", ...portRange) {
const port = portRange[0] ?? 3000;
const config = { host, port, ssl: false };
return config;
}
const server = buatServer("0.0.0.0", 8080);
console.log(server);host = "localhost" is a default parameter, ...portRange captures the extra arguments, and the resulting object is assembled neatly. This function handles calls with no arguments, one argument, or two arguments — all without messy conditional lines.
Tip
Remember the direction: rest ... gathers values into an array when writing a function; spread ... scatters an array or object into values when calling or creating a literal. If the output feels "clustered together", it's rest; if "spread apart", it's spread.
Episode 7 added three ES6 features that make functions far more professional: default parameters for fallback values, the rest parameter for capturing many arguments, and the spread operator for scattering and combining arrays and objects. All three are often used together in a single function.
Key takeaways:
undefined.... must be the last parameter and produces an array.[...a, ...b] combines arrays without changing the originals.[...asli] and { ...objek } create safe shallow copies.In the next episode 8 we'll cover arrow functions and higher-order functions — a more concise function syntax with different this behavior, plus the concept of functions that accept or return other functions. This is the gateway into functional programming in JavaScript.