Tutorials Logic, IN info@tutorialslogic.com

JavaScript this Keyword call, apply, bind

JavaScript Receivers and Construction

Regular-function `this` is chosen by the invocation form, while arrows capture the surrounding binding. The `new` operator creates and links an instance, invokes a constructor with that instance, and selects the final result according to the constructor return value.

Reliable object APIs make receiver requirements visible, bind callbacks at their ownership boundary, enforce derived-constructor ordering, and use factories when creation is asynchronous or can fail normally.

JavaScript this Keyword

JavaScript this keyword refers to the current object. In other words, while executing every JavaScript function has a reference to its current execution context, known as this. In simple, here execution context means how the function is called. JavaScript this has different values depending on where it is used-

Global Context: in a browser script, top-level this usually points to window. In JavaScript modules and strict-mode functions, the value is different and often undefined.

Object's Method: when a function is called with dot notation such as user.sayHi(), this points to the object before the dot.

The call(), apply() and bind() Methods: these methods let you explicitly choose the this value instead of depending on how the function is called.

JavaScript new Keyword

The new keyword is used to create an instances of objects from a constructor function, which has to be placed before the constructor function call and will do the following-

  • It creates a new object and the type of this object is simply object.
  • It sets the new empty objects invisible prototype property(i.e. __proto__) to be the constructor function visible and accessible prototype property.
  • It binds this keyword to the newly created object and executes the constructor function.
  • It returns the newly created object.

Javascript This And New Keyword Worked Example

Javascript This And New Keyword Worked Example
function TutorialsLogic(tutorial) {
  this.tutorial = tutorial;
}
const site = new TutorialsLogic('JavaScript');
console.log(site.tutorial); // JavaScript
console.log(site.__proto__ === TutorialsLogic.prototype); // true

this in Different Contexts

The value of this depends entirely on how a function is called, not where it is defined.

this Contexts

this Contexts
// 1. Global context - this = window (browser) or global (Node.js)
console.log(this === window); // true (browser)

// 2. Object method - this = the object
const person = {
  name: 'Alice',
  greet() {
    return `Hello, I am ${this.name}`;
  }
};
console.log(person.greet()); // Hello, I am Alice

// 3. Regular function - this = undefined (strict) or window (non-strict)
function show() {
  console.log(this); // window or undefined
}

// 4. Arrow function - this = inherited from enclosing scope
const timer = {
  seconds: 0,
  start() {
    setInterval(() => {
      this.seconds++; // 'this' refers to timer object
      console.log(this.seconds);
    }, 1000);
  }
};

// 5. Event handler - this = the element that fired the event
document.getElementById('btn').addEventListener('click', function() {
  console.log(this); // <button> element
});

call(), apply(), and bind()

These three methods let you explicitly set the value of this when calling a function.

call, apply, bind

call, apply, bind
function introduce(greeting, punctuation) {
  return `${greeting}, I am ${this.name}${punctuation}`;
}

const user = { name: 'Bob' };

// call - invoke immediately, args passed individually
console.log(introduce.call(user, 'Hello', '!'));
// Hello, I am Bob!

// apply - invoke immediately, args passed as array
console.log(introduce.apply(user, ['Hi', '.']));
// Hi, I am Bob.

// bind - returns a NEW function with 'this' permanently bound
const boundIntro = introduce.bind(user, 'Hey');
console.log(boundIntro('?'));
// Hey, I am Bob?

// Practical: borrowing methods
const arr = [3, 1, 4, 1, 5, 9];
const max = Math.max.apply(null, arr);
console.log(max); // 9
// Modern equivalent:
console.log(Math.max(...arr)); // 9

Lost Method Receivers

A common mistake is saving a method into a variable and calling it later. The function is no longer called as an object method, so this no longer points to the original object. Use bind(), an arrow wrapper, or call the method through the object.

Lost this

Lost this
"use strict";

const account = {
  owner: "Riya",
  showOwner() {
    return this.owner;
  }
};

const looseFunction = account.showOwner;
// looseFunction(); // TypeError: this is undefined in strict mode

const fixedFunction = account.showOwner.bind(account);
console.log(fixedFunction()); // Riya

// Another safe option:
const wrapper = () => account.showOwner();
console.log(wrapper()); // Riya

Constructor Return Rules

When a constructor is called with new, JavaScript normally returns the newly created object. If the constructor explicitly returns another object, that object replaces the new instance. Returning a primitive value such as a string or number is ignored.

new Return Rules

new Return Rules
function User(name) {
  this.name = name;
  return "ignored";
}

console.log(new User("Aman").name); // Aman

function SpecialUser(name) {
  this.name = name;
  return { name: name, role: "admin" };
}

console.log(new SpecialUser("Maya")); // { name: "Maya", role: "admin" }

Call-Site Binding

`this` is a binding supplied when a regular function is invoked. In `account.balance()`, the receiver before the dot becomes `this` for that call. The same function assigned to another object receives the other object, and a detached call such as `const read = account.balance; read()` loses the original receiver.

A standalone regular-function call receives `undefined` as `this` in strict mode. In a non-strict function, nullish `this` is substituted with the global object and primitive receivers are boxed. Modern modules and class bodies are strict, so code should not depend on global substitution.

`call` invokes with an explicit receiver and individual arguments; `apply` accepts an argument list; `bind` creates a new function with a fixed receiver and optionally leading arguments. Binding an already bound function does not replace its original receiver. Keep the bound function reference when it must later be removed as a listener.

Method ownership and receiver are different concepts. A method inherited through a prototype normally receives the object used at the call site, not the prototype where the function was defined. This is what lets one method operate on many instances.

  • Determine regular-function this from the invocation form.
  • Expect detached strict calls to receive undefined.
  • Use call, apply, or bind only when an explicit receiver is needed.
  • Separate method definition location from call receiver.

Arrow Functions and Callbacks

An arrow function does not create its own `this`; it closes over the binding from the surrounding context. `call`, `apply`, and `bind` cannot replace that captured value. This makes an arrow useful for a nested callback that should retain the outer method receiver, but usually wrong as an object method that needs a dynamic receiver.

Callback APIs decide how regular callbacks are invoked. Array iteration methods normally call a callback without a useful receiver unless a `thisArg` is supplied. Promise handlers and timers should be treated the same way. Pass the required data explicitly or use a lexical arrow instead of assuming the callback remembers its source object.

A DOM listener registered with a normal function commonly receives the listener element as `this`, matching `event.currentTarget`; an arrow retains its outer binding. Prefer `currentTarget` when the element is part of the event contract because it is explicit and easier to type and test.

Class field arrows capture the instance during construction and remain bound when passed around, but each instance receives a separate function. Prototype methods are shared and can be bound only where needed. Choose based on identity, memory, override behavior, and callback ergonomics rather than making every method an arrow.

  • Use arrows to capture an existing receiver, not create one.
  • Treat callback receivers as part of the calling API contract.
  • Prefer event.currentTarget for listener ownership.
  • Balance per-instance field arrows against shared prototype methods.

Construction with new

The `new` operator creates an object whose prototype is the constructor function prototype, invokes the constructor with that object as `this`, and normally returns the object. If the constructor explicitly returns another non-primitive object, that object replaces the created instance; returning a primitive does not replace it.

A constructable function and an ordinary callable function are related but distinct capabilities. Arrow functions and concise methods are not constructors and cannot be used with `new`. Classes require `new` and throw when called as ordinary functions, preventing accidental receiver loss.

The constructor property named `prototype` is not the same as the prototype of the constructor function itself. Instances created by `new C()` normally inherit from `C.prototype`. Replacing that object affects only later instances, while adding a method to the existing prototype is visible to instances sharing it.

`new.target` reports the constructor originally invoked with `new` and is undefined in an ordinary function call. A base constructor can use it to require construction or coordinate subclass behavior, though classes already enforce construction syntax more clearly.

  • Know object creation, prototype linkage, invocation, and return selection.
  • Distinguish callable functions from constructable functions.
  • Do not confuse a constructor prototype property with its own prototype.
  • Use classes when construction invariants benefit from enforced new.

Classes and Derived Construction

A base class constructor receives the newly created instance as `this`. A derived constructor has no initialized `this` until `super()` successfully runs, so reading fields, calling instance methods, or returning implicitly before `super()` throws. Call `super()` once on every path that continues with the derived instance.

Instance field initializers run for each instance in construction order, while static fields and static blocks run with the class as `this`. Instance methods still use dynamic call-site receivers. Extracting `const save = editor.save` therefore loses the instance unless the method is bound or wrapped.

Private fields are checked against the receiver brand. Calling a class method with an unrelated object through `call` may fail even if that object has similarly named public fields. Do not expose methods as freely reusable callbacks when they require branded private state.

Prefer factories when creation can fail normally, return cached implementations, or choose among unrelated concrete types. Constructors should establish a valid instance synchronously. Avoid starting unowned asynchronous work inside a constructor; expose an async factory or explicit initialization method with clear failure and cleanup behavior.

  • Initialize derived this through super before use.
  • Expect extracted prototype methods to lose their instance receiver.
  • Respect private-field receiver branding.
  • Use async factories for fallible asynchronous creation.

Receiver Debugging and Design

When `this` is wrong, pause inside the function and inspect the exact invocation expression. Search for extraction, callback registration, destructuring, rebinding, proxy forwarding, and wrapper functions. The function definition alone cannot explain a regular function receiver.

Log constructor name or stable object identity only in temporary diagnostics; avoid serializing an entire receiver that may contain cycles or secrets. A stack trace plus call-site breakpoint usually reveals more than printing `this` after it has already been passed through wrappers.

APIs that do not need dynamic receivers are easier to compose when they accept dependencies and data as explicit parameters. Use `this` for cohesive object or class behavior, not as a hidden transport for arbitrary context. Document methods that must remain attached or bind them at the ownership boundary.

Tests should cover method calls, detached calls, bound calls, callbacks, subclass instances, constructor object returns, and attempts to construct non-constructable functions where relevant. Assert state and prototype relationships, not only one output value.

  • Debug the invocation expression before editing the function.
  • Prefer explicit parameters when no object receiver is required.
  • Bind at the boundary that owns callback identity.
  • Test invocation and prototype edge cases.
Before you move on

JavaScript this Keyword call, apply, bind Mastery Check

5 checks
  • Identify the exact invocation form before predicting this.
  • Use arrows only when lexical receiver capture is intended.
  • Distinguish callability from constructability.
  • Call super before using this in a derived constructor.
  • Test detached, bound, callback, and constructor edge cases.
Browse Free Tutorials

Explore 500+ free tutorials across 20+ languages and frameworks.