πŸ“’
SDV503
  • SDV503
  • Command Prompt
    • Windows Command Prompt
    • Mac OS Terminal
  • GIT & GITHub
    • GitHub
    • Git
      • Git Workflow
        • Forking Workflow
  • README
    • How to write a readme.md file?
    • Write a better README.me
    • Generate a README for GitHub Repo Quickly
  • Code-comments
    • Clean Comments
    • Writing Comments in a Good way
  • Pair Coding
    • What is Pair Coding?
    • Pair Programming Experience
  • Programming?
    • What is Programming?
    • What Is A Programming Paradigm?
    • JavaScript Programming Paradigms
  • Number Systems
    • Decimal and Binary numbers
  • JavaSCript
    • Introduction To JavaScript
      • The JavaScript Engine
  • JS Call Stack
    • JavaScript call stack
    • JavaScript & Memory
      • Memory Leaks in JavaScript
    • Execution Context and Execution Stack in Javascript
      • Javascript Execution Context and Hoisting
  • JavaScript Variables
    • Introduction to JS Data Types
    • Primitive and Non-Primitive
    • Operator precedence and associativity
      • JS Operators Part One
      • JS Operators Part Two
      • JS Operators Part Three
    • Clean Code for JS Variables
  • JavaScript Scopes
    • Scope (Chain) Visualized
  • Javascript β€Šβ€”β€Šthis keyword
  • JavaScript Data Types
    • More JavaScript Data Types
  • JavaScript Expressions and Statements
  • if/else, switch and ternary operator
    • If/Else statement
  • Switch Statement
  • Ternary Operator
  • JavaScript Loops
    • Loops in JavaScript
      • Trouble With Loops
  • Objects
    • JavaScript Objects
      • Prototypal Inheritance Visualized
      • JavaScript Number Object
      • JavaScript String Object
  • Functions
    • JavaScript Function Part One
    • JavaScript Function Part Two
    • Immediately Invoked Function Expressions ~ IIFE
    • JS => Arrow Functions
    • JavaScript Callback
    • Hoisting in JavaScript
      • Hoisting Visualized
    • Recursion Functions
    • Curry and Function Composition
  • JavaScript Features
    • JSpread Operator
    • JavaScript Built-in Functions & Objects
  • Data Structures&Algorithms
    • JavaScript’s Data Types
    • Data Structures in JavaScript
      • Introduction to Big O Notation
      • Big O Notation in Javascript
      • Linked Lists
        • Linked Lists β€” 2
      • Hash Tables
      • Stack & Queue
  • TLDR
    • Single quotes (β€˜ ’) and double quotes (β€œ ”) in JavaScript
  • ES6
    • Generators and Iterators
    • Javascript Classes
    • JavaScript closures
    • JavaScript Promises & Async/Await
      • Event Loop Visualized
  • C#
    • What does C#? (C Sharp)
    • C# vs JavaScript
    • What Is The Difference Between C#, .NET, ASP.NET, Microsoft.NET, and Visual Studio?
    • What is the .NET Framework?
    • Methods and Properties of Console Class in C#
    • Datatypes in C#
    • C# Code Comments
    • The if statement
    • The switch statement
    • Loops
    • Comparison operators
    • Addition assignment operators
    • The String Interpolation Operator
    • Arrays
    • Lists
    • Dictionaries
Powered by GitBook
On this page
  • Core Idea
  • Countdown Function
  • Imperative approach (loops)
  • Recursive approach
  • Debugging our imperative solution
  • Debugging our recursive solution
  • Infinite Loops
  • Infinite Recursion
  • Base case
  • Summary

Was this helpful?

  1. Functions

Recursion Functions

Recursion can feel difficult to new developers. Perhaps that's because many resources teach it using algorithmic examples (Fibonacci, linked-lists). This piece will hopefully introduce things plainly, using one simple example.

Core Idea

Recursion is when a function calls itself until someone stops it. If no one stops it then it'll recurse (call itself) forever.

Recursive functions let you perform a unit of work multiple times. This is exactly what for/while loops let us accomplish! Sometimes, however, recursive solutions are a more elegant approach to solving a problem.

Countdown Function

Let's create a function that counts down from a given number. We'll use it like this.

countDownFrom(5);
// 5
// 4
// 3
// 2
// 1

And here's our algorithm to solve this problem.

  1. Take one parameter called number. This is our starting point.

  2. Go from number down to 0, logging each one along the way.

We'll start with a for loop approach and then compare it to a recursive one.

Imperative approach (loops)

function countDownFrom(number) {
	for (let i = number; i > 0; i--) {
		console.log(i);
	}	
}

countDownFrom(5);
// 5
// 4
// 3
// 2
// 1

This one contains both algorithmic steps.

  1. βœ… Take one parameter called number.

  2. βœ… Log everything from number to 0.

Recursive approach

function countDownFrom(number) {
	if (number === 0) {
		return;
	}

    console.log(number);    
    countDownFrom(number - 1);
}

countDownFrom(5);
// 5
// 4
// 3
// 2
// 1

This one also passes.

  1. βœ… Take one parameter called number.

  2. βœ… Log everything from number to 0.

So conceptually the two approaches are the same. However, they get the job done in different ways.

Debugging our imperative solution

For a more visual example, let's put a debugger in our loop version and throw it into Chrome Developer Tools.

function countDownFrom(number) {
	for (let i = number; i > 0; i--) {
		console.log(i);
		debugger;
	}	
}

See how it uses an extra variable, i, to track the current number? As you iterate i decreases, eventually hitting 0 and terminating.

And in the for loop we specified "stop if i > 0".

Debugging our recursive solution

function countDownFrom(number) {
	if (number === 0) {
		return;
	}

    console.log(number);
	
	debugger;

    countDownFrom(number - 1);
}

The recursive version doesn't need extra variables to track its progress. Notice how the pile of functions (call stack) grows as we recurse?

That's because each call to countDownFrom adds to the stack, feeding it number - 1. By doing this we're we're passing along an updated number each time. No extra state needed!

That's main difference between the two approaches.

  1. Iterative uses internal state (extra variables for counting, etc).

  2. Recursive does not, it simply passes updated parameters between each call.

But how does either version know when to stop?

Infinite Loops

In your travels, you may have been warned about the dreaded infinite loop.

🚨 THIS RUNS FOREVER, BE WARNED 🚨
while (true) { console.log('WHY DID YOU RUN THIS?!' }

🚨 THIS RUNS FOREVER, BE WARNED 🚨
for (i = 0;;) { console.log('WHY DID YOU RUN THIS?!') }

Since they'd theoretically run forever, an infinite loop will halt your program and possibly crash your browser. You can prevent them by always coding a stopping condition.

βœ… This does not run forever
x = 0;
while (x < 3) { console.log(x); x++; }

βœ… This does not run forever
for (x = 0; x < 3; x++) { console.log(x); }

In both cases we log x, increment it, and stop when it becomes 3. Our countDownFrom function had similar logic.

// Stop at 0
for (let i = number; i > 0; i--)

Again, loops need extra state to determine when they should stop. That's what x and i are for.

Infinite Recursion

Recursion also presents the same danger. It's not hard to write a self-referencing function that'll crash your browser.

🚨THIS RUNS FOREVER, BE WARNED🚨
function run() {
    console.log('running');
    run();
}

run();
// running
// running
// ...

Without a stopping condition, run will forever call itself. You can fix that with an if statement.

βœ… This does not run forever

function run(x) {
    if (x === 3) return;
    
    console.log('running');
    run(x + 1);
}

run(0);
// running
// running
// running

// x is 3 now, we're done.

Base case

This is known as the base case–our recursive countDownFrom had one.

if (number === 0) {
    return;
}

It's the same idea as our loop's stopping logic. Whichever approach you pick, always remember that at some point it needs to be stopped.

Summary

  • Recursion is when a function calls itself until someone stops it.

  • It can be used instead of a loop.

  • If no one stops it, it'll recurse forever and crash your program.

  • A base case is a condition that stops the recursion. Don't forget to add them!

  • Loops use extra state variables for tracking and counting, while recursion only uses the provided parameters.

PreviousHoisting VisualizedNextCurry and Function Composition

Last updated 5 years ago

Was this helpful?

countdownFrom-iterative
countdownFrom-recursive