Functions — Declarations, Expressions, Arrow
JS-এর বড় ধারণা — function একটি value
1. Three Function Forms
// 1. Declaration — hoisted; can be called above its definition
function add(a, b) { return a + b; }
// 2. Expression — assigned to a variable; not hoisted
const sub = function (a, b) { return a - b; };
// 3. Arrow — concise; lexical this; cannot be a constructor
const mul = (a, b) => a * b;
console.log(add(2, 3), sub(5, 1), mul(4, 6));
2. Functions Are Values
Functions are first-class objects. You can assign them, pass them, store them in arrays, and return them from other functions.
const ops = [
a => a + 1,
a => a * 2,
a => a - 3
];
const result = ops.reduce((acc, fn) => fn(acc), 10);
console.log(result); // ((10+1)*2)-3 = 19
function runTwice(fn, x) {
return fn(fn(x));
}
console.log(runTwice(n => n + 1, 5)); // 7
3. Arrow Function Forms
// Single param, expression body — implicit return
const sq = n => n * n;
// Multiple params — parens required
const hyp = (a, b) => Math.sqrt(a * a + b * b);
// Block body — explicit return needed
const greet = name => {
const hr = new Date().getHours();
const tag = hr < 12 ? "morning" : "afternoon";
return `Good ${tag}, ${name}`;
};
// Returning an object — wrap in parens
const point = (x, y) => ({ x, y });
console.log(sq(7), hyp(3, 4), greet("Arif"), point(2, 5));
4. Default & Rest Parameters
// Default values — used only when arg is undefined
function power(base, exp = 2) { return base ** exp; }
console.log(power(5)); // 25
console.log(power(5, 3)); // 125
// Rest — collects extra args into an array
function sum(...nums) {
return nums.reduce((a, b) => a + b, 0);
}
console.log(sum(1, 2, 3, 4)); // 10
// Combine — defaults + rest
function log(prefix = "[info]", ...messages) {
console.log(prefix, ...messages);
}
log(undefined, "hello", "world"); // [info] hello world
5. The Big Difference — this
Regular functions get their own this based on how they're called. Arrow functions inherit this from the enclosing scope. This single rule is the reason arrow functions exist.
const counter = {
count: 0,
// Regular method — `this` is `counter`
tick() {
this.count++;
console.log("method:", this.count);
},
// Arrow method — DOES NOT WORK as a method!
bad: () => {
// `this` here is the OUTER scope (not counter)
console.log("arrow this:", this);
},
// Arrow inside method — keeps `this` of method
delayedTick() {
setTimeout(() => {
this.count++;
console.log("timer:", this.count);
}, 0);
}
};
counter.tick();
counter.tick();
counter.delayedTick();
this নেই — এটি enclosing scope থেকে আসে। তাই callback বা inner function-এ arrow ব্যবহার করলে this ঠিক থাকে। কিন্তু object method হিসেবে arrow ব্যবহার করবেন না।6. Hoisting Rules
✅ Declarations are hoisted
hi(); // works
function hi() { console.log("hi"); }
⚠️ Expressions / arrow not
hi(); // TypeError
const hi = () => console.log("hi");
7. IIFE — Immediately Invoked
An IIFE creates a private scope. Less needed since ES Modules — but still useful for one-off setup.
const result = (() => {
const secret = 42;
return secret * 2;
})();
console.log(result); // 84
8. Glossary (শব্দকোষ)
| Term | Meaning | বাংলায় |
|---|---|---|
| Function declaration | function name() {} — hoisted; callable above its line. | function name() {} — hoisted, declaration-এর আগেও call করা যায়। |
| Function expression | A function assigned to a variable; not hoisted. | Variable-এ assign করা function — hoisted নয়। |
| Arrow function | (args) => expr — concise, no own this. | সংক্ষিপ্ত — নিজের this নেই, parent-এর scope থেকে আসে। |
| First-class | Functions can be assigned, passed, returned like any value. | Function-কে value-র মতো assign/pass/return করা যায়। |
| IIFE | Immediately Invoked Function Expression — runs once on definition. | সংজ্ঞার সাথে সাথে চলে এমন function। |
| Default parameter | Fallback used when argument is undefined. | Argument undefined হলে যে fallback ব্যবহার হয়। |
| Rest parameter | ...args — collects extra arguments into an array. | ...args — অতিরিক্ত argument-গুলো array-তে জমে। |
this | The receiver of a method call; depends on how the function is called. | Method call-এর receiver — কে call করেছে তার উপর নির্ভর করে। |
this নেই — তাই callback এবং inner function-এ এটি প্রায়ই সঠিক, কিন্তু object method হিসেবে arrow ব্যবহার করবেন না। Default parameter আর rest ...args পুরোনো arguments object-এর জায়গায় বেশি পরিষ্কার।
9. Practice Problems
- Write a function
squarein three different ways (declaration, expression, arrow).✨ Show Answer
a1.jsfunction sq1(n) { return n * n; } const sq2 = function (n) { return n * n; }; const sq3 = n => n * n; console.log(sq1(5), sq2(5), sq3(5)); - Compute the average of any number of arguments.
✨ Show Answer
a2.jsconst avg = (...nums) => nums.reduce((a, b) => a + b, 0) / nums.length; console.log(avg(10, 20, 30)); // 20 - Write
greet(name, msg = "হ্যালো").✨ Show Answer
a3.jsconst greet = (name, msg = "হ্যালো") => `${msg}, ${name}!`; console.log(greet("Arif")); console.log(greet("Nusrat", "Welcome")); - Build a function that takes a function and a number, returning the function applied n times.
✨ Show Answer
a4.jsconst repeat = (fn, n) => x => { let r = x; for (let i = 0; i < n; i++) r = fn(r); return r; }; const add5twice = repeat(x => x + 5, 2); console.log(add5twice(3)); // 13 - Show that arrow function inherits
thisby using setTimeout inside an object method.✨ Show Answer
a5.jsconst obj = { name: "Arif", say() { setTimeout(() => console.log(this.name), 0); } }; obj.say(); // "Arif" - Build an
addthat supportsadd(2)(3)currying.✨ Show Answer
a6.jsconst add = a => b => a + b; console.log(add(2)(3)); // 5 const add5 = add(5); console.log(add5(10)); // 15 - Show that calling a function declaration above its definition works, but calling an arrow above doesn't.
✨ Show Answer
a7.jsdeclared(); function declared() { console.log("hoisted!"); } try { arrow(); } catch (e) { console.log("err:", e.message); } const arrow = () => console.log("never"); - Write an arrow that returns an object literal.
✨ Show Answer
a8.jsconst mkUser = name => ({ name, ts: Date.now() }); console.log(mkUser("Arif")); - Write a higher-order
oncethat ensures a function runs at most once.✨ Show Answer
a9.jsconst once = fn => { let done = false, val; return (...args) => { if (!done) { val = fn(...args); done = true; } return val; }; }; const init = once(() => { console.log("init!"); return 42; }); init(); init(); init(); // "init!" only once - Build a function that returns its own arity (number of declared params).
✨ Show Answer
a10.jsfunction f(a, b, c) {} console.log(f.length); // 3 const g = (a, b = 5, ...rest) => {}; console.log(g.length); // 1 (stops before defaults/rest) - Use IIFE to compute pi using a series and return the value.
✨ Show Answer
a11.jsconst pi = (() => { let s = 0; for (let i = 0; i < 100000; i++) s += (i % 2 ? -1 : 1) / (2 * i + 1); return s * 4; })(); console.log(pi); - Why can't you use
newon an arrow function?✨ Show Answer
Answer: Arrow functions don't have their own
thisbinding, noprototypeproperty, and no[[Construct]]internal slot — calling them withnewthrows "X is not a constructor". Use a regular function or a class for object construction. - Use rest parameters and the spread operator together.
✨ Show Answer
a13.jsconst max = (...n) => Math.max(...n); const nums = [3, 9, 1, 7]; console.log(max(...nums)); // 9 - Build a function
memothat caches results by argument.✨ Show Answer
a14.jsconst memo = fn => { const cache = new Map(); return x => cache.has(x) ? cache.get(x) : (cache.set(x, fn(x)), cache.get(x)); }; const slow = n => { console.log("compute", n); return n * n; }; const fast = memo(slow); console.log(fast(3)); // compute 3, 9 console.log(fast(3)); // 9 (cached) - Show that
argumentsdoesn't exist inside an arrow function.✨ Show Answer
a15.jsfunction classic() { console.log(arguments.length); } classic(1, 2, 3); // 3 const arr = (...args) => console.log(args.length); arr(1, 2, 3); // 3 (use rest) - Write a tag-aware logger:
logger("DB")(message).✨ Show Answer
a16.jsconst logger = tag => msg => console.log(`[${tag}]`, msg); const dbLog = logger("DB"); dbLog("connected"); dbLog("query OK");
Summary — Module 11
Three function forms — declarations are hoisted, expressions and arrows are not. Arrow functions inherit this from the enclosing scope, making them the right choice for callbacks but the wrong choice for object methods. Default and rest parameters cover the cases the old arguments object handled awkwardly.
this নেই — callback-এ ভালো, method-এ খারাপ।