FUNCTIONS (PART 2) IN JAVASCRIPT
This note explains the arguments pseudo-array, default parameters, function expressions, scope, scope chain, and the call stack in simple language.
These topics are very important because they explain how functions really behave in JavaScript.
1. The arguments pseudo-array
When you call a regular function, JavaScript automatically creates a special variable inside it:
arguments
This variable contains all arguments that were passed to the function.
Example
function sum(a, b) {
console.log(arguments);
return a + b;
}
sum(2, 5);
When sum(2, 5) runs, arguments contains 2 and 5.
Diagram 1. What arguments contains
Function call:
sum(2, 5)
Inside the function:
arguments
│
├─ arguments[0] → 2
├─ arguments[1] → 5
└─ length → 2
Explanation
Even if you already have named parameters like a and b, JavaScript still gives you arguments with all passed values.
2. Why it is called a pseudo-array
arguments looks like an array, but it is not a real array.
That is why it is called a pseudo-array or array-like object. It has some array behavior, but not all.
It can do these things
- has
length - elements can be accessed by index
- can be iterated with a loop
But it cannot do these things directly
- it does not have normal array methods like
join(),push(), andslice()
Diagram 2. arguments vs real array
arguments
│
├─ has indexes → yes
├─ has length → yes
├─ works in loops → yes
└─ has array methods → no
Real array
│
├─ has indexes → yes
├─ has length → yes
├─ works in loops → yes
└─ has array methods → yes
Explanation
This is the most important thing to remember: arguments is array-like, but not a real array.
3. Accessing values inside arguments
You can read its values by index.
function showArgs() {
console.log(arguments[0]);
console.log(arguments[1]);
console.log(arguments.length);
}
showArgs("apple", "banana");
Output
apple
banana
2
Diagram 3. Access by index
showArgs("apple", "banana")
arguments[0] → "apple"
arguments[1] → "banana"
arguments.length → 2
Explanation
It works very much like an array for basic reading.
4. Iterating over arguments
Because arguments can be iterated, you can loop through all passed values.
function multiply() {
let total = 1;
for (const arg of arguments) {
total *= arg;
}
return total;
}
console.log(multiply(1, 2, 3)); // 6
console.log(multiply(1, 2, 3, 4)); // 24
console.log(multiply(1, 2, 3, 4, 5)); // 120
Diagram 4. How multiply() works with arguments
Call:
multiply(1, 2, 3, 4)
arguments:
[1, 2, 3, 4] ← pseudo-array idea
total = 1
↓
1 * 1 = 1
↓
1 * 2 = 2
↓
2 * 3 = 6
↓
6 * 4 = 24
↓
return 24
Explanation
This is useful when you do not know in advance how many arguments the function will receive.
5. Converting arguments to a real array
If you want to use real array methods, convert arguments into a real array.
Array.from(arguments)
Example
function foo() {
const args = Array.from(arguments);
return args.join("-");
}
console.log(foo(1, 2, 3)); // "1-2-3"
Diagram 5. Converting arguments
arguments
↓ Array.from(arguments)
real array
↓
now array methods work
Explanation
After conversion, you can use methods like join(), slice(), push(), and other array methods.
6. Step by step for Array.from(arguments)
function foo() {
const args = Array.from(arguments);
return args.join("-");
}
console.log(foo(1, 2, 3));
Diagram 6. Full flow
foo(1, 2, 3)
↓
arguments = {0: 1, 1: 2, 2: 3, length: 3}
↓
Array.from(arguments)
↓
[1, 2, 3]
↓
join("-")
↓
"1-2-3"
Explanation
This shows why conversion is useful.
7. Default parameters
A function parameter can have a default value. That value is used when no argument is passed for that parameter.
function greet(username = "Guest") {
console.log(`Hello, ${username}!`);
}
greet("Jacob"); // "Hello, Jacob!"
greet(); // "Hello, Guest!"
Diagram 7. Default parameter logic
greet("Jacob")
username = "Jacob"
greet()
username = "Guest"
Explanation
If an argument exists, it replaces the default value. If no argument is passed, the default value is used.
8. Why default parameters are useful
Default parameters make functions more flexible.
They help you avoid writing extra checks like “Was a value passed?” or “Should I use some basic value instead?”
Diagram 8. Why defaults help
Without default:
need extra check
With default:
function already knows fallback value
Explanation
This makes code shorter and easier to read.
9. Example with more than one parameter
function count(from, to, step = 1) {
console.log(`from: ${from}, to: ${to}, step: ${step}`);
for (let i = from; i <= to; i += step) {
// ...
}
}
count(1, 15, 4); // "from: 1, to: 15, step: 4"
count(1, 15); // "from: 1, to: 15, step: 1"
Diagram 9. How step = 1 works
count(1, 15, 4)
step = 4
count(1, 15)
step = 1 ← default value
Explanation
If the third argument is missing, JavaScript uses 1.
10. Important idea about default parameters
Default values are used only when the argument is missing.
function greet(name = "Guest") {
console.log(name);
}
greet(); // "Guest"
Diagram 10. Default parameter rule
Argument passed?
│
├─ yes → use passed value
└─ no → use default value
Explanation
This is the simple rule for default parameters.
11. Function declaration
You already know this syntax:
function multiply(x, y, z) {
console.log(x * y * z);
}
This is called a function declaration.
Diagram 11. Function declaration structure
function multiply(x, y, z) {
console.log(x * y * z);
}
1. function keyword
2. function name
3. parameters
4. function body
Explanation
This is the classic way to create a function.
12. Function expression
A function expression is when a function is stored inside a variable.
const multiply = function (x, y, z) {
console.log(x * y * z);
};
multiplyis a variable- its value is a function
Diagram 12. Function expression structure
const multiply = function (x, y, z) {
console.log(x * y * z);
};
1. const variable
2. variable name = multiply
3. function is the value
Explanation
This is another valid way to create functions in JavaScript.
13. Function declaration vs function expression
These two styles look similar, but behave differently.
Function declaration
function multiply(x, y, z) {
console.log(x * y * z);
}
Function expression
const multiply = function (x, y, z) {
console.log(x * y * z);
};
Diagram 13. Main difference
Function declaration
→ can be called before its code appears
Function expression
→ can only be called after variable creation
Explanation
This is one of the most important differences.
14. Calling a function expression too early
This does not work:
multiply(1, 2, 3); // Error
const multiply = function (x, y, z) {
console.log(x * y * z);
};
This causes an error because the variable does not exist yet at the moment of the first call.
Diagram 14. Why early call fails
Step 1:
try to run multiply(1, 2, 3)
Step 2:
JavaScript has not created const multiply yet
Result:
Error
Explanation
A function expression is stored in a variable, so the variable must be created first.
15. Calling a function expression after creation
This works:
const multiply = function (x, y, z) {
console.log(x * y * z);
};
multiply(4, 5, 6); // works
Diagram 15. Correct order for function expression
1. Create variable multiply
2. Store function in it
3. Call multiply()
Explanation
You must always call a function expression after the place where it is created.
16. Function declarations can be called earlier
This works:
multiply(1, 2, 3);
function multiply(x, y, z) {
console.log(x * y * z);
}
multiply(4, 5, 6);
Diagram 16. Function declaration calling order
Call multiply()
↓
JavaScript already knows function declaration
↓
works
Explanation
Function declarations behave differently from function expressions in this way.
17. Which style should you use?
Both styles are valid. The important thing is consistency.
Diagram 17. Best practice idea
Project style
│
├─ use function declarations consistently
or
└─ use function expressions consistently
Explanation
Mixing too many styles can make code harder to read.
18. What is scope?
Scope decides where variables are available in code.
A variable can be used if it is in the current scope or in an outer scope.
Diagram 18. What scope means
Scope = visibility area of a variable
Explanation
Scope answers this question: “Where can I use this variable?”
19. Global scope
A variable declared outside functions and blocks is in the global scope.
const globalValue = 10;
console.log(globalValue); // 10
function foo() {
console.log(globalValue); // 10
}
for (let i = 0; i < 5; i += 1) {
console.log(globalValue); // 10
if (i === 2) {
console.log(globalValue); // 10
}
}
Diagram 19. Global variable visibility
Global scope
│
└─ globalValue = 10
Available:
- outside all blocks
- inside function foo()
- inside for block
- inside if block
Explanation
Global variables can be used in many places after they are declared.
20. Block scope
Variables declared inside blocks {} belong only to that block.
Examples of block scope include if, for, and functions.
function foo() {
const a = 20;
console.log(a); // 20
for (let i = 0; i < 5; i += 1) {
console.log(a); // 20
if (i === 2) {
console.log(a); // 20
}
}
}
console.log(a); // Error
Diagram 20. Local variable in function scope
function foo() {
const a = 20;
}
Inside foo():
a exists
Outside foo():
a does not exist
Explanation
The variable a is local to the function. Outside the function, JavaScript cannot see it.
21. Scope chain
Scopes form a hierarchy. This is called the scope chain.
A child scope can access variables from its parent scope. But a parent scope cannot access variables from inner child scopes.
Diagram 21. Scope chain as levels
Global
│
└─ Function scope
│
└─ for block
│
└─ if block
Explanation
Code can look outward to parent scopes, but not inward to child scopes.
22. House and rooms idea
You can imagine scope like a house with rooms.
- the house = global scope
- each function or block = new room
Variables in one room stay inside that room.
Diagram 22. House model of scope
House = Global scope
Room A = function
Room B = if block
Room C = for block
Explanation
If a variable is in Room B, you can use it inside Room B. But outside that room, it is unavailable.
23. Nested block scope example
for (let i = 0; i < 5; i += 1) {
const a = 20;
console.log(a); // 20
if (i === 2) {
const b = 30;
console.log(a); // 20
console.log(b); // 30
}
if (i === 3) {
console.log(a); // 20
console.log(b); // Error
}
}
Diagram 23. Nested block visibility
for block
│
├─ a exists
│
└─ if (i === 2) block
└─ b exists
Outside that if block:
b does not exist
Explanation
b only lives inside the block where it was created.
24. How JavaScript looks for variables
When JavaScript sees a variable name, it searches step by step:
- current scope
- parent scope
- next outer scope
- global scope
If it still cannot find the variable, it throws an error.
Diagram 24. Variable lookup process
Need variable?
↓
Look in current scope
↓
Not found?
↓
Look in outer scope
↓
Not found?
↓
Look in global scope
↓
Still not found?
↓
Error
Explanation
This is the basic rule of the scope chain.
25. Example with global name collision
{
const name = "Aaron";
console.log(name); // "Aaron"
}
console.log(name); // global variable name
Diagram 25. Same variable name in different scopes
Inside block:
name = "Aaron"
Outside block:
name = global name
Explanation
A local variable can hide another variable with the same name from an outer scope. This is why naming matters.
26. What is the call stack?
When functions call other functions, JavaScript needs a way to remember which function is running now, which function called it, and where to return after a function finishes.
That mechanism is the call stack.
Diagram 26. What the call stack does
Call stack
│
├─ remembers active function calls
├─ tracks current execution order
└─ knows where to return next
Explanation
Without the call stack, JavaScript would not know how to control nested function calls.
27. JavaScript is single-threaded
JavaScript runs one instruction at a time.
- it cannot fully run many functions at the same instant
- each function must wait for inner calls to finish first
Diagram 27. Single-threaded idea
JavaScript
↓
one instruction at a time
↓
current function pauses while inner function runs
Explanation
This is why function calls happen in a strict order.
28. Example with nested function calls
function fnA() {
console.log("Log inside fnA function before calling fnB");
fnB();
console.log("Log inside fnA function after fnB call");
}
function fnB() {
console.log("Log inside fnB function");
}
console.log("Log before calling fnA");
fnA();
console.log("Log after calling fnA");
Output
Log before calling fnA
Log inside fnA function before calling fnB
Log inside fnB function
Log inside fnA function after fnB call
Log after calling fnA
Diagram 28. Order of execution with fnA and fnB
1. "Log before calling fnA"
2. call fnA()
3. inside fnA → log before fnB
4. call fnB()
5. inside fnB → log
6. fnB ends
7. return to fnA
8. fnA logs after fnB
9. fnA ends
10. "Log after calling fnA"
Explanation
The outer function pauses while the inner function runs. After the inner function finishes, JavaScript returns to the paused place.
29. Stack idea: LIFO
A stack works using the rule Last In, First Out (LIFO).
That means the last thing added is the first thing removed.
Diagram 29. Stack model
Top of stack
│
├─ newest item
├─ older item
└─ oldest item
Explanation
Imagine a stack of plates. You put new plates on top, and you also take plates from the top.
30. Call stack and function calls
When a function is called:
- JavaScript adds it to the call stack
- executes it
- if it calls another function, that new function goes on top
- when a function finishes, it is removed
- execution returns to the previous function
Diagram 30. Call stack rules
Function called
↓
push to stack
↓
execute
↓
finished?
↓
remove from stack
↓
return to previous call
Explanation
This is how JavaScript keeps order in nested function calls.
31. Example with foo, bar, and baz
function bar() {
console.log("bar");
}
function baz() {
console.log("baz");
}
function foo() {
console.log("foo");
bar();
baz();
}
foo();
Diagram 31. Step-by-step call stack
Step 1:
Call foo()
Stack:
[ foo ]
Step 2:
Inside foo() → call bar()
Stack:
[ foo, bar ]
Step 3:
bar() ends
Stack:
[ foo ]
Step 4:
Inside foo() → call baz()
Stack:
[ foo, baz ]
Step 5:
baz() ends
Stack:
[ foo ]
Step 6:
foo() ends
Stack:
[ ]
Explanation
Each new function call goes on top of the stack. When it finishes, it is removed.
32. What is a stack frame?
Each function call creates a stack frame.
A stack frame stores information like function name, where it was called, and internal execution data.
Diagram 32. Stack frame idea
One function call
↓
one stack frame
Stack frame stores:
- function info
- call location
- execution state
Explanation
You do not usually work with stack frames directly, but they are part of how the call stack works.
33. Why the call stack matters
The call stack helps JavaScript keep order, return to the correct place, manage nested function calls, and report useful errors.
Diagram 33. Why call stack is useful
Call stack
│
├─ controls order
├─ remembers paused functions
├─ allows return to correct place
└─ helps detect stack overflow
Explanation
This is why the call stack is a core JavaScript mechanism.
34. Stack overflow
The call stack is not infinite. It has limited memory.
If too many function calls are added without stopping, JavaScript throws this error:
Uncaught RangeError: Maximum call stack size exceeded
Diagram 34. Stack overflow idea
Function call
↓
another function call
↓
another function call
↓
another function call
↓
stack grows too much
↓
RangeError
Explanation
This usually happens when function calls never stop.
35. Why stack overflow can happen
A common reason is endless recursion. That means a function keeps calling itself forever.
Example of bad recursion
function foo() {
foo();
}
foo();
This never stops, so the stack keeps growing until it crashes.
Diagram 35. Endless recursion
foo()
↓
foo()
↓
foo()
↓
foo()
↓
... never stops
↓
stack overflow
Explanation
Every new call adds another frame to the stack. If there is no stopping condition, memory runs out.
36. Common beginner mistakes
Mistake 1. Thinking arguments is a real array
Wrong idea:
arguments.join("-")
This may fail because arguments is not a true array.
Better:
const args = Array.from(arguments);
args.join("-");
Mistake 2. Forgetting that default values are used only when argument is missing
If an argument is passed, the default is not used.
Mistake 3. Calling a function expression before creation
multiply(1, 2);
const multiply = function (x, y) {
return x * y;
};
Mistake 4. Trying to use local variables outside their scope
function test() {
const a = 10;
}
console.log(a); // Error
Mistake 5. Thinking parent scope can access child variables
Outer code cannot access variables declared only inside inner blocks.
Diagram 36. Common mistakes summary
1. arguments is not a real array
2. default parameters work only when argument is missing
3. function expressions must be called after creation
4. local variables stay inside their scope
5. child scope can see parent scope, not the other way around
Explanation
These are very common beginner problems in this topic.
37. Quick summary
arguments
A special pseudo-array with all passed arguments.
Pseudo-array
Array-like value with indexes and length, but without normal array methods.
Array.from(arguments)
Converts arguments into a real array.
Default parameters
Parameter values used when no argument is passed.
Function expression
A function stored in a variable.
Function declaration
A function declared with the function keyword directly.
Scope
The area where a variable is available.
Scope chain
A hierarchy where inner scopes can access outer scopes.
Global scope
Variables declared outside all blocks and functions.
Block scope
Variables declared inside {} and available only there.
Call stack
The structure that tracks active function calls.
Stack overflow
An error caused by too many unfinished function calls.
Diagram 37. Final map of Functions Part 2
Functions (Part 2)
│
├─ arguments
│ ├─ pseudo-array
│ └─ Array.from()
│
├─ default parameters
│
├─ function expression
│
├─ scope
│ ├─ global
│ ├─ local
│ └─ scope chain
│
└─ call stack
├─ stack frames
└─ stack overflow
Explanation
This is the complete picture of the topic.
38. Revision block
1. arguments contains all passed arguments
2. arguments is not a real array
3. Array.from(arguments) creates a real array
4. Default parameters are used when an argument is missing
5. A function expression is a function stored in a variable
6. Function expressions must be called after they are created
7. Scope controls where variables are visible
8. Inner scopes can access outer scopes
9. Outer scopes cannot access inner variables
10. The call stack tracks active function calls
11. JavaScript uses Last-In-First-Out order in the call stack
12. Endless function calls can cause stack overflow
39. Final conclusion
This topic explains some of the deeper behavior of functions in JavaScript.
If you understand how arguments works, why it is a pseudo-array, how default parameters work, how function expressions differ from declarations, how scope and scope chain work, and how the call stack works, then your understanding of JavaScript functions becomes much stronger.
These ideas are very important for full stack development because they appear in reusable function design, parameter handling, nested logic, debugging, recursion, and real program execution flow.