Functions — Declarations, Expressions, Arrow

JS-এর বড় ধারণা — function একটি value

~35 min Intermediate 16 practice problems Live runner

1. Three Function Forms

forms.js
// 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));
তিন রকম function — declaration, expression এবং arrow। Modern code-এ অধিকাংশ সময় arrow function বা declaration ব্যবহার হয়।

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.

first-class.js
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

arrows.js
// 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

params.js
// 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.

this.js
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();
Arrow function-এর নিজস্ব 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.

iife.js
const result = (() => {
    const secret = 42;
    return secret * 2;
})();
console.log(result);   // 84

8. Glossary (শব্দকোষ)

TermMeaningবাংলায়
Function declarationfunction name() {} — hoisted; callable above its line.function name() {} — hoisted, declaration-এর আগেও call করা যায়।
Function expressionA function assigned to a variable; not hoisted.Variable-এ assign করা function — hoisted নয়।
Arrow function(args) => expr — concise, no own this.সংক্ষিপ্ত — নিজের this নেই, parent-এর scope থেকে আসে।
First-classFunctions can be assigned, passed, returned like any value.Function-কে value-র মতো assign/pass/return করা যায়।
IIFEImmediately Invoked Function Expression — runs once on definition.সংজ্ঞার সাথে সাথে চলে এমন function।
Default parameterFallback used when argument is undefined.Argument undefined হলে যে fallback ব্যবহার হয়।
Rest parameter...args — collects extra arguments into an array....args — অতিরিক্ত argument-গুলো array-তে জমে।
thisThe receiver of a method call; depends on how the function is called.Method call-এর receiver — কে call করেছে তার উপর নির্ভর করে।
সারাংশ: Function একটি value। Declaration hoisted, expression/arrow নয়। Arrow-এর নিজস্ব this নেই — তাই callback এবং inner function-এ এটি প্রায়ই সঠিক, কিন্তু object method হিসেবে arrow ব্যবহার করবেন না। Default parameter আর rest ...args পুরোনো arguments object-এর জায়গায় বেশি পরিষ্কার।

9. Practice Problems

  1. Write a function square in three different ways (declaration, expression, arrow).
    ✨ Show Answer
    a1.js
    function 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));
  2. Compute the average of any number of arguments.
    ✨ Show Answer
    a2.js
    const avg = (...nums) =>
        nums.reduce((a, b) => a + b, 0) / nums.length;
    console.log(avg(10, 20, 30));   // 20
  3. Write greet(name, msg = "হ্যালো").
    ✨ Show Answer
    a3.js
    const greet = (name, msg = "হ্যালো") => `${msg}, ${name}!`;
    console.log(greet("Arif"));
    console.log(greet("Nusrat", "Welcome"));
  4. Build a function that takes a function and a number, returning the function applied n times.
    ✨ Show Answer
    a4.js
    const 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
  5. Show that arrow function inherits this by using setTimeout inside an object method.
    ✨ Show Answer
    a5.js
    const obj = {
        name: "Arif",
        say() {
            setTimeout(() => console.log(this.name), 0);
        }
    };
    obj.say();   // "Arif"
  6. Build an add that supports add(2)(3) currying.
    ✨ Show Answer
    a6.js
    const add = a => b => a + b;
    console.log(add(2)(3));   // 5
    const add5 = add(5);
    console.log(add5(10));    // 15
  7. Show that calling a function declaration above its definition works, but calling an arrow above doesn't.
    ✨ Show Answer
    a7.js
    declared();
    function declared() { console.log("hoisted!"); }
    
    try { arrow(); }
    catch (e) { console.log("err:", e.message); }
    const arrow = () => console.log("never");
  8. Write an arrow that returns an object literal.
    ✨ Show Answer
    a8.js
    const mkUser = name => ({ name, ts: Date.now() });
    console.log(mkUser("Arif"));
  9. Write a higher-order once that ensures a function runs at most once.
    ✨ Show Answer
    a9.js
    const 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
  10. Build a function that returns its own arity (number of declared params).
    ✨ Show Answer
    a10.js
    function f(a, b, c) {}
    console.log(f.length);    // 3
    
    const g = (a, b = 5, ...rest) => {};
    console.log(g.length);    // 1 (stops before defaults/rest)
  11. Use IIFE to compute pi using a series and return the value.
    ✨ Show Answer
    a11.js
    const 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);
  12. Why can't you use new on an arrow function?
    ✨ Show Answer

    Answer: Arrow functions don't have their own this binding, no prototype property, and no [[Construct]] internal slot — calling them with new throws "X is not a constructor". Use a regular function or a class for object construction.

  13. Use rest parameters and the spread operator together.
    ✨ Show Answer
    a13.js
    const max = (...n) => Math.max(...n);
    const nums = [3, 9, 1, 7];
    console.log(max(...nums));   // 9
  14. Build a function memo that caches results by argument.
    ✨ Show Answer
    a14.js
    const 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)
  15. Show that arguments doesn't exist inside an arrow function.
    ✨ Show Answer
    a15.js
    function classic() { console.log(arguments.length); }
    classic(1, 2, 3);   // 3
    
    const arr = (...args) => console.log(args.length);
    arr(1, 2, 3);       // 3 (use rest)
  16. Write a tag-aware logger: logger("DB")(message).
    ✨ Show Answer
    a16.js
    const 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.

Function একটি value। Declaration hoisted, arrow নয়। Arrow-এর নিজস্ব this নেই — callback-এ ভালো, method-এ খারাপ।

Next Module → Higher-Order Functions & Closures।