HomeBytesheetsRoadmapsUI TemplatesUI ToolsStack Discussion
5 Topics
Chapter•80 Minutes

Functions, Closures, this, and Function Composition

Understand JavaScript functions as first-class values, closures, callback behavior, this binding, arrow functions, and advanced function patterns.

Functions Are First-Class Values

Functions can be assigned to variables, stored in objects, passed as arguments, returned from other functions, and dynamically constructed. This enables callbacks, higher-order functions, event handlers, middleware, composition, and functional programming techniques.

A function declaration and a function expression both create callable functions, but their declaration and initialization behavior differs.

Passing Functions Around
function double(value) {
  return value * 2;
}

function transform(value, operation) {
  return operation(value);
}

console.log(transform(5, double));
💡 The transform function receives another function as an argument. This is the basis of higher-order functions.
Key Takeaways
  • Functions are values in JavaScript.
  • Functions can be passed, returned, stored, and composed.
  • Higher-order functions accept or return functions.
Knowledge Check

What is a higher-order function?

Closures: The Real Mental Model

A closure is created when a function retains access to variables from its lexical environment even after the outer function has finished executing. The important concept is not merely 'a function inside another function'; it is that the inner function retains access to the relevant lexical bindings.

Closures are used for private state, factories, memoization, callbacks, module patterns, and asynchronous code.

Private State with a Closure
function createCounter() {
  let count = 0;

  return function increment() {
    count += 1;
    return count;
  };
}

const counter = createCounter();
console.log(counter());
console.log(counter());
💡 createCounter returns after creating the inner function, but the returned function still has access to count. The binding remains reachable through the closure.
Key Takeaways
  • Closures preserve access to lexical bindings.
  • Closures are useful for encapsulation and state.
  • A closure retains reachable bindings, not necessarily every variable from the entire outer scope.
Knowledge Check

Why does `count` remain available after `createCounter()` returns?

How `this` Is Determined

Unlike lexical variables, this is generally determined by how a function is called. With a normal function, the call site matters. obj.method() gives this as obj. A standalone call in strict mode gives undefined. call, apply, and bind can explicitly control this.

Arrow functions are different: they do not create their own this; they capture this lexically from their surrounding context.

Method vs Detached Function
const user = {
  name: 'Suriya',
  greet() {
    return this.name;
  }
};

console.log(user.greet());

const greet = user.greet;
console.log(greet());
💡 The first call has user as its receiver. The detached call no longer has that receiver, so in strict mode this is undefined and accessing this.name throws.
Key Takeaways
  • this is not simply the same thing as lexical scope.
  • Normal function this depends on invocation.
  • Arrow functions capture this lexically.
Knowledge Check

What does an arrow function do with `this`?

call, apply, and bind

call invokes a function immediately with a specified this and individual arguments. apply does the same but receives arguments as an array-like collection. bind does not invoke immediately; it creates a new function with a permanently bound this and optionally pre-filled arguments.

These methods are especially useful when adapting APIs, creating callbacks, or working with methods that need an explicit receiver.

Binding a Method
const user = {
  name: 'Suriya'
};

function greet(prefix) {
  return `${prefix}, ${this.name}`;
}

const greetUser = greet.bind(user, 'Hello');
console.log(greetUser());
💡 bind returns a new function. The new function uses user as this and pre-fills the prefix argument.
Key Takeaways
  • call invokes immediately with individual arguments.
  • apply invokes immediately with an argument collection.
  • bind returns a new function for later invocation.
Knowledge Check

Which method returns a new function instead of immediately invoking the original function?

Map, Filter, Reduce, and Function Composition

Methods such as map, filter, and reduce are higher-order operations over collections. map transforms every element, filter selects elements, and reduce combines values into an accumulator. They are not merely shortcuts; they express different computational intentions.

Composition becomes especially useful when small pure functions are combined into larger transformations.

A Collection Pipeline
const numbers = [1, 2, 3, 4, 5, 6];

const result = numbers
  .filter(n => n % 2 === 0)
  .map(n => n * n)
  .reduce((sum, n) => sum + n, 0);

console.log(result);
💡 The pipeline first selects even values, then squares them, and finally sums the resulting values.
Key Takeaways
  • map transforms elements.
  • filter selects elements.
  • reduce models accumulation into one result.
Knowledge Check

Which method is most directly intended to transform every element into another value?