Skip to main content

Explicitly setting this in JavaScript

You can force this with the methods call, apply and bind, and also through calling the function as a method of an object, through arrow functions, Reflect.apply and the new operator. The difference between them is when the call happens and whether the context can be changed afterwards.

Theory

TL;DR

  • call(thisArg, a, b) invokes the function immediately, arguments comma separated.
  • apply(thisArg, [a, b]) does the same, but the arguments come as an array.
  • bind(thisArg) does not invoke anything, it returns a new function with a bound this.
  • obj.method() sets this = obj implicitly.
  • Arrow functions have no this of their own and take it from the enclosing scope.
  • Reflect.apply(fn, thisArg, args) is the modern counterpart of apply.
  • new Func() creates a new object and overrides even a bind binding.

Quick example

javascript
function greet() { console.log(`Hello, I am ${this.name}`); } const user = { name: 'Maria' }; greet.call(user); // Hello, I am Maria

Here this inside greet is forced to point at user.

call and apply: immediate invocation with a given context

Function.prototype.call() invokes the function immediately and lets you set this by hand:

javascript
function greet() { console.log(`Hello, I am ${this.name}`); } const user = { name: 'Maria' }; greet.call(user); // Hello, I am Maria

apply() does the same thing as call, but takes the arguments as an array:

javascript
function introduce(city, job) { console.log(`I am ${this.name} from ${city}, working as a ${job}`); } const user = { name: 'Maria' }; introduce.apply(user, ['Kyiv', 'Frontend developer']); // I am Maria from Kyiv, working as a Frontend developer

bind: a new function with a bound context

bind() does not invoke the function right away; it creates a new one whose this is already bound forever:

javascript
function sayHi() { console.log(`Hello, I am ${this.name}`); } const user = { name: 'Maria' }; const sayHiBound = sayHi.bind(user); sayHiBound(); // Hello, I am Maria

The difference:

  • call / apply invoke immediately;
  • bind creates a copy with a fixed context.

Implicit context: object methods and arrow functions

If you call a function through the dot on an object, this automatically points at that object:

javascript
const user = { name: 'Maria', sayHi() { console.log(`Hello, I am ${this.name}`); } }; user.sayHi(); // Hello, I am Maria

This is an implicit assignment of this, but in essence the same thing.

Arrow functions have no this of their own: they inherit it from the enclosing scope:

javascript
const user = { name: 'Maria', sayHiLater() { setTimeout(() => { console.log(`Hello, I am ${this.name}`); // this = user }, 1000); } }; user.sayHiLater(); // Hello, I am Maria

Had a regular function been used inside setTimeout, this would have been lost and become window.

Reflect.apply, new and deliberately dropping the context

Reflect.apply() is the modern ES6 counterpart of apply: it does the same, but more safely and declaratively, because it does not depend on whether apply has been overridden on the function itself:

javascript
function sayHello() { console.log(`Hello, ${this.name}`); } const user = { name: 'Maria' }; Reflect.apply(sayHello, user, []); // Hello, Maria

When a function is called with new, a new object is created and this inside the function points at it, even if a different this was bound through bind:

javascript
function User(name) { this.name = name; } const Bound = User.bind({ name: 'Maria' }); const u = new Bound('Alice'); console.log(u.name); // Alice, the context from new overrides bind

If instead you want to "unbind" this and call the function without a context, you pass null or undefined:

javascript
function showThis() { console.log(this); } showThis.call(null); // under 'use strict' -> undefined

In sloppy mode null is substituted with the global object (window or global).

Summary of the options

WayInvokes immediatelyHow it sets thisArguments
call(thisArg, a, b)YesForcedComma separated
apply(thisArg, [a, b])YesForcedAs an array
bind(thisArg, a, b)NoBinds foreverComma separated
obj.method()YesImplicitly (this = obj)Comma separated
Reflect.apply()YesForced (modern counterpart)As an array
new Func()YesA new object inside the functionConstructor arguments

Common mistakes

  • Binding this to an arrow function. Arrows have no this of their own, so call, apply and bind have no effect on it and the first argument is simply ignored.
  • Looking for Reflect.call. No such method exists: Reflect only has apply, so the arguments always go in as an array.
  • Assuming bind invokes the function. It only returns a new function, and without parentheses nothing happens.
  • Counting on window in strict mode. In modules and classes this stays undefined when given null, so this.name throws.
  • Losing the context when passing a method around. setTimeout(user.sayHi, 1000) passes only the function without the object; you need user.sayHi.bind(user) or an arrow wrapper.

Short Answer

Interview ready
Premium

A concise answer to help you respond confidently on this topic during an interview.