Basic of JavaScript — Chapter 6
Learn HTML, CSS, and JavaScript Programming from Beginner to Expert
Welcome back to Chapter 6 of our JavaScript Basics series ! 🎉
You’ve already mastered the fundamentals: variables, loops, functions, parameters, and return values. Now it’s time to dive deeper into some advanced yet beginner-friendly features that will elevate your JavaScript skills. These tools will help you write cleaner , more reusable , and powerful code .
In this chapter, we’ll explore:
- Rest Parameter : Handling an indefinite number of arguments
- Function as Value : Treating functions like any other variable
- Anonymous Function : Functions without names
- Function within a Function : Nesting functions for better organization
- Scope : Understanding variable visibility in different contexts
- Recursive Function : Functions that call themselves
- Function Generator : Creating iterators with
function* - Arrow Function : A modern, concise way to write functions
Each section includes real-life examples , hands-on practice , and clear explanations so you can confidently apply these concepts to your own projects.
Let’s get started!
Rest Parameter
The rest parameter (...) allows you to pass an indefinite number of arguments to a function. It collects all remaining arguments into an array, making your functions more flexible and dynamic.
Here’s the basic structure:
function name(...args) {
// args is an array of all passed arguments
}Let’s see how the rest parameter works with real-world examples.
Example 1: Summing Numbers Dynamically
You can use the rest parameter to sum any number of inputs.
function sum(...numbers) {
let total = 0;
for (let num of numbers) {
total += num;
}
return total;
}
console.log(sum(1, 2, 3)); // 6
console.log(sum(10, 20, 30, 40)); // 100✅ What Happens?
The sum function accepts any number of arguments and calculates their total — perfect for calculators , dynamic forms , and data aggregation .
Example 2: Logging Arguments
You can use the rest parameter to log all arguments passed to a function.
function logArguments(...args) {
console.log("Arguments:", args);
}
logArguments("Hello", "World", 42); // Arguments: ["Hello", "World", 42]✅ What Happens?
This logs all arguments as an array — useful for debugging , logging , and inspecting inputs .
Example 3: Combining Arrays and Individual Values
You can mix regular parameters with the rest parameter.
function greet(message, ...names) {
for (let name of names) {
console.log(`${message}, ${name}!`);
}
}
greet("Hello", "Alice", "Bob", "Charlie");
// Output:
// Hello, Alice!
// Hello, Bob!
// Hello, Charlie!✅ What Happens?
This combines a fixed parameter (message) with a dynamic list of names — great for personalized messages , notifications , and batch processing .
Summary
In this section, you’ve learned how to use the rest parameter to handle an indefinite number of arguments in a clean and organized way.
You explored:
- How to sum numbers dynamically
- How to log all arguments
- How to combine fixed and dynamic parameters
The rest parameter makes your functions flexible , scalable , and dynamic — empowering you to build adaptable applications .
Next, let’s explore how functions can be treated like any other value in JavaScript.
Function as Value
In JavaScript, functions are first-class citizens , meaning they can be assigned to variables, passed as arguments, or returned from other functions. This flexibility allows you to create highly modular and reusable code.
Let’s see how functions behave as values with practical examples.
Example 1: Assigning a Function to a Variable
You can assign a function to a variable just like any other value.
let greet = function(name) {
console.log(`Hello, ${name}!`);
};
greet("Alice"); // Hello, Alice!✅ What Happens?
The function greet is stored in a variable — demonstrating how functions are treated like values .
Example 2: Passing Functions as Arguments
You can pass functions as arguments to other functions.
function processUserInput(callback) {
let name = prompt("Enter your name:");
callback(name);
}
processUserInput(function(name) {
console.log(`Welcome, ${name}!`);
});✅ What Happens?
The processUserInput function takes another function (callback) as an argument and calls it with user input — widely used in event handling , API calls , and asynchronous programming .
Example 3: Returning Functions
You can return a function from another function.
function createMultiplier(multiplier) {
return function(value) {
return value * multiplier;
};
}
let double = createMultiplier(2);
let triple = createMultiplier(3);
console.log(double(5)); // 10
console.log(triple(5)); // 15✅ What Happens?
This creates reusable functions (double, triple) by returning them from createMultiplier — ideal for factory functions , configuration , and custom logic .
Summary
In this section, you’ve learned how to treat functions as values in JavaScript.
You explored:
- How to assign functions to variables
- How to pass functions as arguments
- How to return functions from other functions
Treating functions as values makes your code modular , reusable , and highly customizable .
Next, let’s explore anonymous functions , which don’t have names but are incredibly useful.
Anonymous Function
An anonymous function is a function without a name. It’s often used when you need a quick, one-off function that doesn’t require reuse.
Here’s the basic structure:
function() {
// Code to execute
}Let’s see how anonymous functions work with real examples.
Example 1: Using Anonymous Functions as Callbacks
You can use anonymous functions as callbacks in event listeners.
document.getElementById("button").addEventListener("click", function() {
alert("Button clicked!");
});✅ What Happens?
When the button is clicked, the anonymous function runs — commonly used in event handling , DOM manipulation , and UI interactions .
Example 2: Filtering Arrays
You can use anonymous functions with methods like filter.
let numbers = [1, 2, 3, 4, 5];
let evens = numbers.filter(function(num) {
return num % 2 === 0;
});
console.log(evens); // [2, 4]✅ What Happens?
This filters out even numbers using an anonymous function — perfect for data processing , transformations , and filtering logic .
Example 3: Inline Calculations
You can use anonymous functions for quick calculations.
let result = (function(a, b) {
return a + b;
})(5, 7);
console.log(result); // 12✅ What Happens?
This immediately invokes the anonymous function to calculate the result — useful for one-time operations , initialization , and self-contained logic .
Summary
In this section, you’ve learned how to use anonymous functions for quick, one-off tasks.
You explored:
- How to use them as callbacks
- How to filter arrays
- How to perform inline calculations
Anonymous functions are simple, concise, and ideal for short-lived operations .
Next, let’s explore functions within functions , also known as nested functions.
Function dalam Function (Nested Functions)
A nested function is a function defined inside another function. This allows you to organize code better, encapsulate logic, and avoid polluting the global scope.
Let’s see how nested functions work with real examples.
Example 1: Encapsulating Logic
You can use nested functions to break down complex tasks.
function calculateArea(width, height) {
function multiply(a, b) {
return a * b;
}
return multiply(width, height);
}
console.log(calculateArea(5, 10)); // 50Example 2: Creating Helper Functions
You can use nested functions as helper utilities.
function processUserData(user) {
function formatName(firstName, lastName) {
return `${lastName}, ${firstName}`;
}
return `User: ${formatName(user.firstName, user.lastName)}`;
}
let user = { firstName: "Alice", lastName: "Smith" };
console.log(processUserData(user)); // User: Smith, Alice✅ What Happens?
This formats the user’s name using a helper function — useful for modularity , readability , and reuse .
Example 3: Closures
Nested functions can access variables from their parent function, creating closures.
function createCounter() {
let count = 0;
return function() {
count++;
return count;
};
}
let counter = createCounter();
console.log(counter()); // 1
console.log(counter()); // 2✅ What Happens?
This creates a closure that retains the count variable — widely used in state management , private variables , and advanced patterns .
Summary
In this section, you’ve learned how to use nested functions to organize and encapsulate logic.
You explored:
- How to break down complex tasks
- How to create helper functions
- How to work with closures
Nested functions make your code modular , encapsulated , and efficient .
Next, let’s explore scope , which determines where variables are accessible.
Scope
Scope defines the visibility and lifetime of variables in JavaScript. Understanding scope helps you manage data effectively and avoid bugs caused by naming conflicts.
Get Riki Graha’s stories in your inbox
Join Medium for free to get updates from this writer.
There are three types of scope:
- Global Scope : Variables declared outside all functions
- Function Scope : Variables declared inside a function
- Block Scope : Variables declared inside curly braces
{}(introduced withletandconst)
Let’s see how scope works with real examples.
Example 1: Global vs Local Scope
Variables in global scope are accessible everywhere, while local variables are limited to their function.
let globalVar = "I'm global";
function testScope() {
let localVar = "I'm local";
console.log(globalVar); // I'm global
console.log(localVar); // I'm local
}
testScope();
console.log(globalVar); // I'm global
// console.log(localVar); // ReferenceError: localVar is not defined✅ What Happens?
Global variables are accessible everywhere, but local variables are confined to their function.
Example 2: Block Scope with let and const
Variables declared with let and const are block-scoped.
if (true) {
let blockVar = "I'm block-scoped";
console.log(blockVar); // I'm block-scoped
}
// console.log(blockVar); // ReferenceError: blockVar is not defined✅ What Happens? blockVar is only accessible inside the block — making let and const safer than var.
Example 3: Avoiding Naming Conflicts
Using block scope prevents naming conflicts.
function test() {
let x = 10;
if (true) {
let x = 20; // Different variable
console.log(x); // 20
}
console.log(x); // 10
}
test();✅ What Happens?
The inner x doesn’t overwrite the outer x — showing how block scope avoids conflicts.
Summary
In this section, you’ve learned about scope and how it affects variable visibility.
You explored:
- The difference between global and local scope
- How
letandconstcreate block scope - How to avoid naming conflicts
Understanding scope helps you write clean , maintainable , and bug-free code .
Next, let’s explore recursive functions , which call themselves to solve problems.
Recursive Function
A recursive function is a function that calls itself until a base condition is met. Recursion is often used to solve problems that can be broken into smaller, similar subproblems.
Here’s the basic structure:
function recursiveFunction(params) {
if (baseCondition) {
return result;
}
return recursiveFunction(modifiedParams);
}Let’s see how recursion works with real examples.
Example 1: Calculating Factorial
You can use recursion to calculate factorials.
function factorial(n) {
if (n === 0 || n === 1) {
return 1;
}
return n * factorial(n - 1);
}
console.log(factorial(5)); // 120✅ What Happens?
This multiplies numbers recursively — commonly used in mathematical algorithms , tree traversal , and divide-and-conquer strategies .
Example 2: Traversing Nested Objects
You can use recursion to traverse deeply nested objects.
let nestedObject = {
a: 1,
b: {
c: 2,
d: {
e: 3
}
}
};
function flatten(obj) {
let result = {};
for (let key in obj) {
if (typeof obj[key] === "object") {
let temp = flatten(obj[key]);
for (let subKey in temp) {
result[subKey] = temp[subKey];
}
} else {
result[key] = obj[key];
}
}
return result;
}
console.log(flatten(nestedObject));
// { a: 1, c: 2, e: 3 }✅ What Happens?
This flattens the nested object into a single-level structure — useful in data normalization , API responses , and deep cloning .
Example 3: Fibonacci Sequence
You can use recursion to generate the Fibonacci sequence.
function fibonacci(n) {
if (n <= 1) {
return n;
}
return fibonacci(n - 1) + fibonacci(n - 2);
}
console.log(fibonacci(7)); // 13✅ What Happens?
This generates the nth Fibonacci number — demonstrating recursion’s power in solving sequence-based problems .
Summary
In this section, you’ve learned how to use recursive functions to solve problems step by step.
You explored:
- How to calculate factorials
- How to traverse nested objects
- How to generate Fibonacci sequences
Recursion is a powerful tool for breaking down complex problems into simpler ones.
Next, let’s explore function generators , which allow you to create iterators with function*.
Function Generator
A function generator is a special kind of function that returns an iterator. It uses the yield keyword to pause and resume execution, making it ideal for working with streams of data.
Here’s the basic structure:
function* name() {
yield value;
}Let’s see how generators work with real examples.
Example 1: Simple Iterator
You can use a generator to create an iterator.
function* generateNumbers() {
yield 1;
yield 2;
yield 3;
}
let generator = generateNumbers();
console.log(generator.next().value); // 1
console.log(generator.next().value); // 2
console.log(generator.next().value); // 3✅ What Happens?
The generator produces values one at a time — perfect for lazy evaluation , stream processing , and custom iterators .
Example 2: Infinite Sequences
You can use generators to create infinite sequences.
function* generateId() {
let id = 1;
while (true) {
yield id++;
}
}
let idGenerator = generateId();
console.log(idGenerator.next().value); // 1
console.log(idGenerator.next().value); // 2✅ What Happens?
This generates unique IDs indefinitely — useful in ID generation , unique keys , and simulations .
Example 3: Yielding Promises
You can use generators with asynchronous code.
function* asyncGenerator() {
yield new Promise(resolve => setTimeout(() => resolve("First"), 1000));
yield new Promise(resolve => setTimeout(() => resolve("Second"), 1000));
}
let gen = asyncGenerator();
gen.next().value.then(console.log); // First (after 1 second)
gen.next().value.then(console.log); // Second (after 1 second)✅ What Happens?
This pauses execution until each promise resolves — demonstrating how generators integrate with async workflows .
Summary
In this section, you’ve learned how to use function generators to create iterators and handle lazy evaluation .
You explored:
- How to create simple iterators
- How to generate infinite sequences
- How to work with promises
Generators are powerful for managing data streams , lazy loading , and asynchronous programming .
Finally, let’s explore arrow functions , a modern and concise way to write functions.
Arrow Function
Arrow functions (=>) were introduced in ES6 as a shorter syntax for writing functions. They also have a lexical this binding , which makes them behave differently from traditional functions.
Here’s the basic structure:
const name = (parameters) => {
// Code to execute
};Let’s see how arrow functions work with real examples.
Example 1: Simplifying Function Syntax
You can use arrow functions to write shorter, cleaner functions.
const greet = (name) => `Hello, ${name}!`;
console.log(greet("Alice")); // Hello, Alice!✅ What Happens?
This replaces a traditional function with an arrow function — reducing boilerplate and improving readability.
let numbers = [1, 2, 3, 4, 5];
let doubled = numbers.map(num => num * 2);
console.log(doubled); // [2, 4, 6, 8, 10]✅ What Happens?
This doubles each number in the array — showing how arrow functions simplify array operations .
Example 3: Lexical this Binding
Arrow functions inherit this from their surrounding context, unlike traditional functions.
function Counter() {
this.count = 0;
setInterval(() => {
this.count++;
console.log(this.count);
}, 1000);
}
new Counter();
// Logs: 1, 2, 3, ...✅ What Happens?
The arrow function preserves this from the Counter instance — avoiding common pitfalls with this binding.
Summary
In this section, you’ve learned how to use arrow functions for cleaner, more concise code.
You explored:
- How to simplify function syntax
- How to work with array methods
- How lexical
thisimproves behavior
Arrow functions make your code shorter , easier to read , and less error-prone .
Final Thoughts
Congratulations! 🎉 You’ve completed Chapter 6 of JavaScript Basics , and now you have a strong foundation in advanced function techniques and control flow .
In this chapter, you learned:
- How to handle indefinite arguments with the rest parameter
- How to treat functions as values
- How to use anonymous functions for quick tasks
- How to organize code with nested functions
- How scope affects variable visibility
- How recursion solves problems step by step
- How generators create iterators
- How arrow functions simplify syntax and improve readability
These tools empower you to write cleaner , smarter , and more efficient JavaScript code — from simple scripts to complex applications .
As you continue your journey, remember: practice makes perfect . Try applying what you’ve learned to real projects, experiment with different patterns, and never stop learning.
You’re doing an amazing job — keep going!
Happy coding! 💻✨








