NexusCS

JavaScript: this

JavaScript
A quick reference for how the this keyword works in every JavaScript context — global, functions, methods, classes, arrow functions, and event handlers.
javascript
this
binding
scope
context

Getting started

Binding priority

Priority Rule this value
1 Arrow function Lexical (enclosing scope)
2 new fn() New object
3 call / apply / bind Specified thisArg
4 obj.fn() obj
5 fn() globalThis or undefined

Higher priority wins. Arrow functions ignore all other rules.

Quick determination

this = ?
├─ Arrow function?
│  └─ Yes → enclosing scope's this
├─ Called with new?
│  └─ Yes → the new object
├─ Called with call/apply/bind?
│  └─ Yes → the specified thisArg
├─ Called as obj.fn()?
│  └─ Yes → obj
└─ Plain fn() call
   ├─ Strict mode → undefined
   └─ Sloppy mode → globalThis

globalThis

globalThis === window; // Browser
globalThis === global; // Node.js
globalThis === self; // Web Worker

Universal reference to the global object. Works in all environments (ES2020).

Global context

Browser vs Node.js

Environment this value
<script> window
<script type="module"> undefined
Node.js CommonJS module.exports
Node.js ESM undefined
Web Worker self

Examples

// Browser <script>
console.log(this === window); // true

// Browser <script type="module">
console.log(this); // undefined

// Node.js CommonJS top-level
console.log(this === module.exports); // true

// Node.js ESM
console.log(this); // undefined

Module contexts always have this === undefined.

Functions

Non-strict mode

function fn() {
  return this;
}
fn(); // globalThis (window in browser)

Without an explicit binding, this defaults to the global object.

Strict mode

"use strict";
function fn() {
  return this;
}
fn(); // undefined

Strict mode prevents accidental global access. ES modules are always strict.

Methods & objects

Object method

const obj = {
  name: "obj",
  getName() {
    return this.name;
  },
};
obj.getName(); // "obj" — this = object before the dot

this is determined by the call site, not where the function is defined.

Prototype chain

const proto = {
  greet() {
    return this.name;
  },
};
const child = Object.create(proto);
child.name = "child";
child.greet(); // "child" — this = child, not proto

this always refers to the object the method was called on, even if the method lives on the prototype.

Constructors

new keyword

function Person(name) {
  this.name = name; // this = new object
}
const p = new Person("Alice");
p.name; // "Alice"

new creates a fresh object and binds this to it.

Return override

function Foo() {
  this.a = 1;
  return { a: 99 }; // overrides this
}
new Foo().a; // 99

function Bar() {
  this.a = 1;
  return 42; // ignored (primitive)
}
new Bar().a; // 1

Returning an object from a constructor replaces this. Returning a primitive is ignored.

Arrow functions

Lexical binding

const obj = {
  name: "outer",
  getNameDelayed() {
    setTimeout(() => {
      console.log(this.name); // "outer"
    }, 100);
  },
};

Arrow functions have no own this — they inherit from the enclosing lexical scope at definition time.

call / apply / bind ignored

const arrow = () => this;

arrow.call({ a: 1 }); // outer this (NOT {a:1})
arrow.apply({ a: 1 }); // outer this
arrow.bind({ a: 1 })(); // outer this

You cannot rebind an arrow function's this. call, apply, and bind are all silently ignored.

Explicit binding

call()

function greet(greeting) {
  return `${greeting}, ${this.name}`;
}
greet.call({ name: "Alice" }, "Hi");
// "Hi, Alice"

Calls immediately. Pass args individually.

apply()

function greet(greeting, punct) {
  return `${greeting}, ${this.name}${punct}`;
}
greet.apply({ name: "Bob" }, ["Hey", "!"]);
// "Hey, Bob!"

Calls immediately. Pass args as array.

bind()

function greet(greeting) {
  return `${greeting}, ${this.name}`;
}
const greetAlice = greet.bind({ name: "Alice" });
greetAlice("Hello"); // "Hello, Alice"

Returns a new function with this permanently bound. Binding only works once — re-binding a bound function is ignored.

Classes

Constructor

class Dog {
  constructor(name) {
    this.name = name; // this = new instance
  }
}
new Dog("Rex").name; // "Rex"

Must call super() before using this in derived classes.

Methods

class Dog {
  constructor(name) {
    this.name = name;
  }
  bark() {
    return `${this.name} says woof`;
  }
  static create(name) {
    return new this(name); // this = Dog class
  }
}

Instance methods: this = instance. Static methods: this = the class itself.

Arrow class fields

class Button {
  constructor(label) {
    this.label = label;
  }
  // Arrow = permanently bound to instance
  handleClick = () => {
    console.log(this.label);
  };
}
const btn = new Button("OK");
const fn = btn.handleClick;
fn(); // "OK" — still works!

Arrow class fields solve the "lost this" problem in callbacks and event handlers.

Event handlers

addEventListener

button.addEventListener("click", function (e) {
  console.log(this === button); // true
  console.log(this === e.currentTarget); // true
});

In a regular function handler, this is the element the listener is attached to (e.currentTarget).

Arrow gotcha

button.addEventListener("click", (e) => {
  console.log(this); // enclosing scope (NOT button!)
  // Use e.currentTarget instead
  console.log(e.currentTarget === button); // true
});

Arrow functions do not receive the element as this. Use e.currentTarget to access the element.

Common gotchas

Losing this

const obj = {
  name: "obj",
  getName() {
    return this.name;
  },
};

// Extracting method
const fn = obj.getName;
fn(); // undefined — lost this!

// Destructuring
const { getName } = obj;
getName(); // undefined — lost this!

// Callback
["a"].forEach(obj.getName); // undefined

Assigning a method to a variable or passing it as a callback detaches it from its object.

Fixes

// Fix 1: Arrow function
["a"].forEach(() => obj.getName());

// Fix 2: bind
["a"].forEach(obj.getName.bind(obj));

// Fix 3: Arrow class field
class Obj {
  name = "obj";
  getName = () => this.name; // always bound
}

setTimeout and setInterval also lose this — use the same fixes.

Also see