The idea
A function is a named, reusable piece of logic: give it inputs, it gives back an output. You've used built-in ones already (console.log, Math.round, Number). Writing your own is how you stop repeating code and start building programs out of small, understandable pieces, exactly like functions in Python.
Declaring and calling
Toko Kita shows prices with 11% VAT included, and that calculation is needed on the product page, in the cart and at checkout. Rather than writing price * 1.11 in all three places, you give the calculation a name once, then use it wherever it's needed:
function addVat(price) {
return Math.round(price * 1.11);
}
console.log(addVat(95000));
console.log(addVat(250000));
105450
277500
function name(parameters) { ... }declares it.returnsends a value back and ends the function. Withoutreturn, a function returnsundefined.- Calling it with
addVat(95000)runs the body withpriceset to95000.
Parameters and defaults
Shipping costs 12000 per kilo for most orders, but sometimes a different rate applies, like express delivery. A default value lets a function use the usual rate unless you say otherwise:
function shippingCost(weightKg, perKg = 12000) {
return weightKg * perKg;
}
console.log(shippingCost(2));
console.log(shippingCost(2, 15000));
console.log(shippingCost());
24000
30000
NaN
- A default (
perKg = 12000) is used when the argument is missing. - JavaScript doesn't complain about missing arguments: they're simply
undefined.undefined * 12000isNaN(Not a Number), which then spreads silently through every calculation. Unlike Python, there's no error to warn you, so be careful with inputs.
Arrow functions
Lots of functions are tiny one-liners, and writing function, the curly braces and return for each one gets wordy. Modern JavaScript has a shorter way to write them, called arrow functions, and you'll see them everywhere:
const addVat = (price) => Math.round(price * 1.11);
const formatRupiah = (amount) => "Rp " + amount.toLocaleString("id-ID");
const greet = () => "Selamat datang!";
const lineTotal = (price, qty) => {
const subtotal = price * qty;
return subtotal > 500000 ? subtotal * 0.95 : subtotal;
};
console.log(formatRupiah(addVat(95000)));
console.log(greet());
console.log(lineTotal(200000, 3));
Rp 105.450
Selamat datang!
570000
(params) => expressionreturns the expression automatically (an implicit return).- With curly braces, you need an explicit
return, like a normal function. - No parameters: empty brackets
(). One parameter: the brackets are optional (price => ...), but many teams keep them for consistency. toLocaleString("id-ID")formats a number the Indonesian way, with dots for thousands.
Arrow functions and function declarations behave the same for everyday use. The differences (this and hoisting) come up in module 9; for now, use arrows for short helpers and callbacks, and either style for named functions.
Functions are values
A function can be stored in a variable, put in an object, or passed to another function. That last one is everywhere in JavaScript:
const prices = [95000, 120000, 45000];
function applyToAll(values, fn) {
const result = [];
for (const value of values) {
result.push(fn(value));
}
return result;
}
console.log(applyToAll(prices, addVatTo));
function addVatTo(price) {
return Math.round(price * 1.11);
}
console.log(applyToAll(prices, (p) => p / 1000 + "k"));
[105450, 133200, 49950]
["95k", "120k", "45k"]
A function passed to another function is called a callback. Event handlers (module 6), array methods like map and filter (module 8) and timers all take callbacks.
Notice that addVatTo was used before its declaration. function declarations are hoisted: JavaScript makes them available throughout their scope. Arrow functions stored in const aren't: using one before its line is an error.
Rest parameters
Sometimes you don't know in advance how many values a function will get. A cart total might be two items or twenty. A rest parameter collects however many arguments are passed into one array:
function total(...amounts) {
let sum = 0;
for (const amount of amounts) sum += amount;
return sum;
}
console.log(total(95000, 120000, 45000));
console.log(total());
260000
0
...amounts collects all the arguments into an array, like *args in Python.
Functions take parameters (with optional defaults) and return a value. Arrow functions ((x) => x * 2) are the compact form, with implicit return for single expressions. Functions are values: store them, and pass them as callbacks.
Why this matters for clean code
Good functions are small, named for what they do, and pure where possible: same inputs, same output, no hidden side effects. addVat(price) can be tested in one line and reused anywhere. A 200-line event handler that calculates VAT inline can't. Most of the rest of this track is about splitting code into functions like these.
Recap
function name(a, b = 1) { return ...; }; noreturnmeansundefined.- Missing arguments are
undefined(no error);undefinedin maths givesNaN. - Arrow functions:
(a, b) => expressionor(a) => { ...; return x; }. - Functions are values; callbacks are functions passed to functions.
functiondeclarations are hoisted;constarrow functions aren't....restcollects remaining arguments into an array.