Functions, arrow functions, and the closure that remembers
Functions are how JavaScript moves. You write a small piece of logic once, give it a name, and call it from anywhere. Sounds boring, except JavaScript gives you three syntaxes for the same idea and one of them quietly changes how this works.
Then there is the closure question, which gets asked in every junior interview. We will fix that too.
Three ways to write a function
function add(a, b) { return a + b; } // declaration
const sub = function (a, b) { return a - b; }; // expression
const mul = (a, b) => a * b; // arrow- Declarations get hoisted. You can call
add()before the line where it is defined. - Expressions are values assigned to a variable. No hoisting, normal scoping rules.
- Arrow functions are short, return implicitly when there is no body braces, and do not bind their own
this.
In modern code, arrow functions are the default for short callbacks. Declarations are still nice for top-level named utilities.
The this problem
this in JavaScript refers to "the object the function was called on." With arrow functions, this comes from the enclosing scope instead.
const cart = {
items: ['samosa', 'chai'],
showRegular() { setTimeout(function () { console.log(this.items); }, 100); },
showArrow() { setTimeout(() => console.log(this.items), 100); },
};showRegular logs undefined. The inner function loses its this. showArrow works, because the arrow inherits this from cart. This single fact is why arrows took over callbacks.
If you are reading old code with a lot of
var self = this;, that is the pre-arrow workaround.
Closures, the chai-stall way
Imagine a chai stall in Indiranagar. The owner keeps a cash-box behind the counter. Customers never touch it. They place an order, the owner adds to the box, and at the end of the day the box has the total.
A closure is the same idea. A function returns another function that secretly keeps access to a variable from its parent.
function makeCashBox() {
let total = 0;
return function add(amount) {
total = total + amount;
return total;
};
}
const stall = makeCashBox();
stall(10); // 10
stall(20); // 30total is hidden. Nothing outside makeCashBox can read or change it. The returned function still has the key. That is a closure.
Where you will actually use closures
- Counters and IDs where state needs to persist between calls.
- Private data in modules, before classes were popular.
- Memoization, caching results of expensive calls.
- Event handlers that need to remember which button they belong to.
Every callback you write in addEventListener, map, setTimeout is a closure. You have been using them without knowing it.
A small recap
- Three ways to write a function. Pick arrow for short callbacks, declaration for named utilities.
- Arrow functions do not have their own
this. That is a feature, not a bug. - Closures are functions that remember the variables they grew up with.
- You use closures in almost every line of modern JS, even if nobody told you.
Next up: arrays and objects, the two data shapes you will use every single day.
Free tools you can use while you learn
Watching quietly. Tap me if you want a tip.
Try this (0 of 2 done)
- 1
Write an arrow function `double` that returns its arg times 2. Log double(7).
show answer
const double = (n) => n * 2; console.log(double(7)); - 2
Build a counter that starts at 100. Call it twice and log both values.
hint
Same closure pattern, just initialise count = 100.
show answer
function counter(start) { let n = start; return () => ++n; } const c = counter(100); console.log(c(), c());