The this Keyword
this refers to the context where code is running. Its value depends on how a function is called (runtime binding), not where it's defined.
Rules (in priority order)
1. new Binding
When a function is called with new, this is the newly created object.
function User(name) {
this.name = name;
}
const user = new User("Ajay");
console.log(user.name); // "Ajay" — this = new object
If the constructor returns a non-primitive, that returned object replaces this:
function Car() {
this.brand = "Toyota";
return { brand: "Honda" }; // overrides `this`
}
console.log(new Car().brand); // "Honda"
2. Explicit Binding — call, apply, bind
function add(c, d) {
return this.a + this.b + c + d;
}
const obj = { a: 1, b: 3 };
add.call(obj, 5, 7); // 16
add.apply(obj, [10, 20]); // 34
const bound = add.bind(obj, 5);
bound(7); // 16
| Method | Arguments | Invokes immediately? |
|---|---|---|
call | (thisArg, a, b, ...) | Yes |
apply | (thisArg, [a, b, ...]) | Yes |
bind | (thisArg, a, b, ...) | No — returns new fn |
bind only works once — re-binding a bound function has no effect:
function f() {
return this.a;
}
const g = f.bind({ a: "first" });
const h = g.bind({ a: "second" }); // ignored
console.log(h()); // "first"
3. Implicit Binding — Object method
this = the object to the left of the dot.
const obj = {
name: "Ajay",
greet() {
console.log(this.name);
},
};
obj.greet(); // "Ajay"
The same function can get different this depending on which object calls it:
function getThis() {
return this;
}
const obj1 = { name: "obj1", getThis };
const obj2 = { name: "obj2", getThis };
console.log(obj1.getThis().name); // "obj1"
console.log(obj2.getThis().name); // "obj2"
Lost binding — extracting a method loses its object:
const fn = obj.greet;
fn(); // undefined — this = window/global (or undefined in strict mode)
4. Default Binding — Standalone function
function show() {
console.log(this);
}
show(); // window (browser) / global (Node) — or undefined in strict mode
Strict Mode vs Non-Strict
| Mode | Standalone this | Primitive this in call/apply |
|---|---|---|
| Non-strict | globalThis | Auto-wrapped to object (7 → Number) |
| Strict | undefined | Stays as-is (7 remains 7) |
function nonStrict() {
return this;
}
console.log(nonStrict()); // window
function strict() {
"use strict";
return this;
}
console.log(strict()); // undefined
Primitive wrapping in non-strict:
function bar() {
console.log(Object.prototype.toString.call(this));
}
bar.call(7); // [object Number]
bar.call("foo"); // [object String]
bar.call(undefined); // [object Window]
Arrow Functions & this
Arrow functions do not have their own this. They capture this from the enclosing lexical scope at definition time. call, apply, bind cannot override it.
const obj = {
name: "Ajay",
// arrow at object level — 'this' is outer (global) scope, NOT obj
greet: () => {
console.log(this.name); // undefined
},
delayedGreet() {
setTimeout(() => {
console.log(this.name); // "Ajay" — arrow inherits from delayedGreet
}, 100);
},
};
const globalObject = this;
const foo = () => this;
console.log(foo() === globalObject); // true
console.log(foo.call({ a: 1 }) === globalObject); // true — call ignored
Class Context
Instance & Static
class C {
instanceField = this; // the instance
static staticField = this; // the class itself
}
const c = new C();
console.log(c.instanceField === c); // true
console.log(C.staticField === C); // true
Derived Class — super() before this
In a subclass constructor, you must call super() before accessing this:
class Base {
constructor() {
this.role = "base";
}
}
class Child extends Base {
constructor() {
super(); // required before using 'this'
this.role = "child";
}
}
Bound Methods in Classes
Binding in constructor prevents this from varying when the method is passed around:
class Car {
constructor() {
this.sayBye = this.sayBye.bind(this);
}
sayHi() {
console.log(`Hello from ${this.name}`);
}
sayBye() {
console.log(`Bye from ${this.name}`);
}
get name() {
return "Ferrari";
}
}
class Bird {
get name() {
return "Tweety";
}
}
const car = new Car();
const bird = new Bird();
bird.sayHi = car.sayHi;
bird.sayHi(); // Hello from Tweety — implicit binding wins
bird.sayBye = car.sayBye;
bird.sayBye(); // Bye from Ferrari — bind locks it
Callbacks
Callbacks lose this because they're called as standalone functions:
function logThis() {
"use strict";
console.log(this);
}
[1, 2, 3].forEach(logThis); // undefined × 3
Some APIs accept a thisArg parameter:
[1, 2, 3].forEach(logThis, { name: "obj" });
// { name: 'obj' } × 3
Getters & Setters
this is the object the property is accessed on:
const stats = {
a: 1,
b: 2,
c: 3,
get average() {
return (this.a + this.b + this.c) / 3;
},
};
console.log(stats.average); // 2
DOM Event Handlers
this is bound to the element that the listener is attached to:
function bluify(e) {
console.log(this === e.currentTarget); // true
this.style.backgroundColor = "#A5D9F3";
}
document.getElementById("btn").addEventListener("click", bluify);
Inline handlers — this = the element:
<button onclick="alert(this.tagName);">Click me</button>
<!-- alerts "BUTTON" -->
Global Context
| Environment | Top-level this |
|---|---|
| Browser script | window |
| ES Module | undefined |
| Node CommonJS | module.exports |
// browser script (not a module)
console.log(this === window); // true
this.x = 42;
console.log(window.x); // 42
Quick Reference
| Context | this value |
|---|---|
| Global (non-strict) | window / globalThis |
| Global (strict) | undefined |
| ES Module (top-level) | undefined |
| Object method | The calling object |
call/apply/bind | The explicitly passed object |
new | The new instance |
| Arrow function | Inherited from enclosing scope |
| Class constructor | The new instance |
| Static method/field | The class itself |
| Event handler (DOM) | The element that fired the event |
| Callback (standalone) | undefined (strict) / globalThis |
| Getter/Setter | The object the property belongs to |
References
Key Takeaways
thisdepends on how the function is called, not where it's written.- Priority:
new> explicit (call/apply/bind) > implicit (object method) > default. - Arrow functions don't have their own
this— they inherit it lexically and it cannot be overridden. bindonly works once — rebinding has no effect.- Strict mode prevents
thisfrom silently defaulting toglobalThis. - In class constructors of derived classes,
super()must be called beforethis.