Frontend Labs
⋯

6. Functions in depth: closures, this, call/apply/bind

Four ways to write a function, with real behavioral differences:

function declared() {}                  // hoisted fully — usable before its definition
const expr = function() {};             // hoisted as `undefined`, only usable after assignment
const arrow = () => {};                 // no own `this`, `arguments`, or `prototype`
class C { method() {} }                 // method shorthand, not enumerable, strict mode always

this is the single most common source of JS confusion. It is NOT lexically scoped for regular functions — it's determined by how the function is called, not where it's defined:

const obj = {
  name: "obj",
  regular: function () { return this.name; },
  arrow: () => { return this?.name; },   // `this` here is captured from the ENCLOSING scope
};

obj.regular();          // "obj" — called as obj.regular(), so `this` = obj
const fn = obj.regular;
fn();                   // undefined (or throws in strict mode) — called bare, `this` is undefined
obj.arrow();            // undefined — arrow functions never bind their own `this`

call/apply/bind explicitly control this:

function greet(greeting) { return `${greeting}, ${this.name}`; }
const person = { name: "Ada" };

greet.call(person, "Hi");     // "Hi, Ada" — invoke immediately, args listed individually
greet.apply(person, ["Hi"]);  // "Hi, Ada" — invoke immediately, args as an array
const bound = greet.bind(person);
bound("Hi");                   // "Hi, Ada" — returns a NEW function permanently bound to `person`

Real-world example. React class components historically needed this.handleClick = this.handleClick.bind(this) in the constructor for exactly this reason — passing this.handleClick as a callback strips it from this. Hooks and arrow-function class fields made this mostly historical, but the underlying this-binding rule hasn't changed.

Generated from real-life-JS-guide.md · 8 Oct 2026 16:36