Episode 1 — Fundamentals / 1.20 — Functions
1.20 — Functions: Quick Revision
Compact cheat sheet. Print-friendly.
How to use this material (instructions)
- Skim before labs or interviews.
- Drill gaps — reopen
README.md→1.20.a…1.20.g. - Practice —
1.20-Exercise-Questions.md. - Polish answers —
1.20-Interview-Questions.md.
Defining functions
| Style | Syntax | Hoisted? |
|---|---|---|
| Declaration | function name() {} | Yes (fully) |
| Expression | const name = function() {} | No |
| Arrow | const name = () => {} | No |
| IIFE | (function() {})() | Runs immediately |
Declaration vs expression
Declaration → hoisted → callable BEFORE the line it appears on
Expression → NOT hoisted → callable ONLY after assignment
Arrow function rules
const a = () => expr; // no params, implicit return
const b = x => expr; // one param (parens optional)
const c = (x, y) => expr; // multiple params
const d = (x) => ({ key: x }); // return object literal — WRAP in ()
const e = (x) => { /* ... */ return val; }; // block body — explicit return
| Feature | Regular | Arrow |
|---|---|---|
Own this | Yes | No (lexical) |
Own arguments | Yes | No |
Constructable (new) | Yes | No |
| Implicit return | No | Yes (no {}) |
Parameters & arguments
Parameters = names in definition Arguments = values in call
Missing argument → undefined Extra arguments → ignored
function fn(a, b = 10, ...rest) { }
// ↑ ↑ default ↑ rest (real Array, must be last)
nulldoes NOT trigger default.undefinedDOES.argumentsobject: legacy, array-like, not in arrows → use...restinstead.
Pass-by-value vs reference behavior
| Passed | Mutation inside fn | Reassignment inside fn |
|---|---|---|
| Primitive | N/A | Does NOT affect outer |
| Object | AFFECTS outer | Does NOT affect outer |
Return values
return value; → sends value back + exits function
no return → returns undefined
return; → returns undefined
Multiple values: return { a, b } or [a, b] and destructure at call site.
Early return: guard clauses at top → flat, readable code.
Scope
| Level | Created by | var | let/const |
|---|---|---|---|
| Global | Top level | Yes | Yes |
| Function | function body | Yes | Yes |
| Block | { } (if, for, etc.) | No | Yes |
Lexical scoping: variable access determined by WHERE the function is WRITTEN, not where called.
Scope chain: current → parent → ... → global. Not found? ReferenceError.
Shadowing: inner variable with same name hides outer one.
Closures
Closure = function + reference to its lexical scope
- Inner function retains access to outer variables after outer function returns.
- Enables: private state, factories, memoization, module pattern.
function make(x) {
return (y) => x + y; // closes over x
}
const add5 = make(5);
add5(3); // 8
Classic bug: var in for loop + setTimeout → all callbacks see final i. Fix: use let.
Pure functions
Same input → ALWAYS same output + NO side effects
Side effects: mutating external state, DOM writes, network calls, console.log, timers.
Strategy: pure core logic + side effects at edges.
Higher-order functions
Takes a function as argument OR returns a function
Built-in: .map(), .filter(), .reduce(), .sort(), .forEach(), setTimeout()
Recursion
function rec(input) {
if (BASE_CASE) return value; // STOP
return rec(smallerInput); // RECURSE toward base
}
- Call stack: one frame per call; too deep → stack overflow.
- Memoization: cache results to avoid redundant calls.
- Best for: trees, nested data, divide-and-conquer.
- TCO: in spec, only Safari supports — do not rely on it.
Naming conventions
| Prefix | Returns | Example |
|---|---|---|
get* | Value | getUser() |
set* | Void/confirm | setTheme() |
is* / has* / can* | Boolean | isValid() |
create* / make* | New thing | createUser() |
handle* | Void (event) | handleClick() |
validate* | Void/throw | validateEmail() |
format* | String | formatDate() |
IIFE
(function () { /* isolated scope */ })();
(() => { /* arrow IIFE */ })();
Purpose: scope isolation, module pattern (pre-ES6), one-time init.
Common pitfalls
| Pitfall | Symptom | Fix |
|---|---|---|
Call expression before const | ReferenceError | Move call after, or use declaration |
| Arrow as object method | this is wrong | Use regular function / shorthand |
() => { key: val } | Returns undefined | Wrap in (): () => ({ key: val }) |
var in loop + async | All callbacks share same i | Use let |
| Recursion no base case | Stack overflow | Add base case |
| Mutation of passed object | Caller's data changed | Shallow copy first |
Master workflow
- Define — declaration (hoisted helper) or arrow (callback/inline).
- Parameters — defaults, rest, destructuring. Validate early.
- Return — explicit value. Early return for guards.
- Scope — minimize globals, prefer
const/let, understand closures. - Reuse — DRY, SRP, pure functions, compose, document with JSDoc.
- Recurse — only for nested/tree data; always have a base case.
End of 1.20 quick revision.