---
title: 'this Binding'
source: 'https://academia.sh/en/courses/javascript-object-model/this-binding'
course: 'Objects and Functions in JavaScript'
language: en
updated: '2026-08-23T07:01:00+00:00'
license: 'CC BY-SA 4.0'
---

# this Binding

Context determined at the call site; the default, implicit, explicit, and constructor binding rules, their priority order, and a method detaching from its object.

Throughout the Prototype Model topic, methods worked through `this`, and this gave the
impression that a function somehow knows the object it was defined on. The impression is
wrong. As in the previous lesson's `Object.assign(copy, this, ...)` call, a function
sitting in a prototype chain can operate on an object it never appeared in at all.

The rule is this: the value of `this` is determined not by where the function is
**defined**, but by **how it is called**. The same function binds to four different
values under four different call forms. This lesson tells the four apart and builds the
priority order among them.

## Default Binding

The plainest call form is calling a function with no object attached to it at all. In
strict mode, the `this` value is `undefined`.

```js
function readBinding() {
  return this;
}

console.log(readBinding() === undefined);
console.log(typeof globalThis);

const nonStrictReadBinding = new Function("return this;");
console.log(nonStrictReadBinding() === globalThis);
console.log(nonStrictReadBinding() === undefined);
```

```
true
object
true
false
```

In non-strict mode, the same call binds `this` to the global object; `globalThis` is
this object's standard name. The difference matters: a method called by accident
without its object throws an error immediately in strict mode, while in non-strict mode
it silently writes a property onto the global object. Because module files and class
bodies run in strict mode, the first is the behavior that applies throughout the
measurement record examples.

## Implicit Binding

If a function is called through a property of an object, `this` binds to that object.
What decides this is the object **to the left** of the dot operator at the call site.

```js
const record = {
  sensor: "S-01",
  value: 21.4,
  time: 1000,
  format() {
    return `${this.sensor}@${this.time}: ${this.value}`;
  },
};

console.log(record.format());

const brokenFormat = record.format;
try {
  console.log(brokenFormat());
} catch (error) {
  console.log(`broken call: ${error.constructor.name}`);
}

const records = [record];
try {
  console.log(records.map(record.format)[0]);
} catch (error) {
  console.log(`callback: ${error.constructor.name}`);
}

console.log(records.map((r) => r.format())[0]);

const measurement = {
  sensor: "S-OUT",
  source: {
    sensor: "S-IN",
    format() {
      return `bind: ${this.sensor}`;
    },
  },
};
console.log(measurement.source.format());
```

```
S-01@1000: 21.4
broken call: TypeError
callback: TypeError
S-01@1000: 21.4
bind: S-IN
```

The second and third lines show the language's most commonly hit trap. The expression
`record.format` gives a function **value**; the bond with the object is not carried
inside this value. Once the value is assigned to a variable or passed as a callback,
the call site changes and binding falls back to the default rule. Because `this` is
`undefined` in strict mode, reading `this.sensor` throws an error.

This is a consequence of the observation in the Programming Fundamentals course's Value
and Reference, and Passing lesson: what is passed is the function itself, not the
context it sits in. The fix on the fourth line is the most direct one — writing a
wrapper that makes the call through the object.

The last line shows that chain length plays no role: only the **last** link counts. In
the call `measurement.source.format()`, `this` is the `source` object; the outer
`measurement` is never considered at all.

## Explicit Binding

The `call`, `apply`, and `bind` operations state the context explicitly at the call
site. Their details are the next lesson's subject; here, only the fact that this rule
is a third form is shown.

```js
const measurementBehavior = {
  format() {
    return `${this.sensor}@${this.time}: ${this.value}`;
  },
};

const chained = Object.create(measurementBehavior);
chained.sensor = "S-01";
chained.value = 21.4;
chained.time = 1000;

const foreign = { sensor: "S-99", value: 5.5, time: 7 };

console.log(chained.format());
console.log(measurementBehavior.format.call(foreign));
console.log(chained.format.call(foreign));
console.log(Object.getPrototypeOf(foreign) === measurementBehavior);
```

```
S-01@1000: 21.4
S-99@7: 5.5
S-99@7: 5.5
false
```

The last line confirms this lesson's opening claim: the `foreign` object's chain
carries no measurement behavior, yet the same function works on its data without
trouble. The prototype chain determines **where the function is found**; `this`
determines **which data it works on**. The two are independent of each other.

## Constructor Binding

The `new` operator binds `this` to the newly created object, in the second of the
steps ordered in the second lesson.

```js
function MeasurementRecord(sensor, value) {
  this.sensor = sensor;
  this.value = value;
}
MeasurementRecord.prototype.format = function () {
  return `${this.sensor}: ${this.value}`;
};

const viaConstructor = new MeasurementRecord("S-01", 21.4);
console.log(viaConstructor.format());
console.log(Object.getPrototypeOf(viaConstructor) === MeasurementRecord.prototype);

try {
  MeasurementRecord("S-02", 19.8);
} catch (error) {
  console.log(`without new: ${error.constructor.name}`);
}

class ClassRecord {
  constructor(sensor) {
    this.sensor = sensor;
  }
  format() {
    return `class: ${this.sensor}`;
  }
}

const instance = new ClassRecord("S-03");
console.log(instance.format());

const broken = instance.format;
try {
  broken();
} catch (error) {
  console.log(`class method broken: ${error.constructor.name}`);
}
```

```
S-01: 21.4
true
without new: TypeError
class: S-03
class method broken: TypeError
```

The third line shows how calling a constructor function without `new` turns out in
strict mode: because `this` is `undefined`, the first assignment throws an error. Class
syntax forbidding this call outright exists precisely to prevent this silent failure.

The last line repeats an important point: class syntax does not solve the detachment
problem. Class methods are also plain functions sitting on the prototype, and they lose
their binding the same way once separated from their object.

## Losing Context in a Callback

The four rules also explain where errors come from. When a method passes a function
into another function inside its body, that function becomes a **separate call**; the
outer method's context does not carry over to it.

```js
const collector = {
  unit: "C",
  measurements: [21.4, 22.8, 20.1],
  formattedList() {
    return this.measurements.map(function (value) {
      return `${value}${this.unit}`;
    });
  },
  formattedListThisArg() {
    return this.measurements.map(function (value) {
      return `${value}${this.unit}`;
    }, this);
  },
};

try {
  console.log(collector.formattedList());
} catch (error) {
  console.log("in callback:", error.constructor.name, "-", error.message);
}

console.log(collector.formattedListThisArg());
```

```
in callback: TypeError - Cannot read properties of undefined (reading 'unit')
[ '21.4C', '22.8C', '20.1C' ]
```

In the first call, the callback function falls to default binding; because `this` is
undefined in strict mode, reading the property throws an error. Some array methods
take a second parameter that binds the callback to a given object; the second call
uses it.

This parameter is not present in every interface. The general fix is one of two steps:
fixing context with explicit binding (next lesson) or using a function form that
establishes no `this` binding of its own (third lesson). The root of the problem is
that the call site is independent of where the function was defined.

## Priority Order

When more than one rule looks like it applies at once, which one wins is fixed:
constructor binding overrides explicit binding; explicit binding overrides implicit
binding; implicit binding overrides default binding.

```js
function writeSensor(sensor) {
  this.sensor = sensor;
  return this;
}

const target = { sensor: "start" };
const otherTarget = { sensor: "other" };

const bound = writeSensor.bind(target);

bound("explicit-bound");
console.log(target.sensor);

otherTarget.run = bound;
otherTarget.run("implicit-attempt");
console.log(target.sensor);
console.log(otherTarget.sensor);

const produced = new bound("constructor");
console.log(produced.sensor);
console.log(target.sensor);
console.log(Object.getPrototypeOf(produced) === writeSensor.prototype);

const obj = {
  sensor: "implicit",
  read() {
    return this.sensor;
  },
};
console.log(obj.read());
console.log(obj.read.call(otherTarget));
```

```
explicit-bound
implicit-attempt
other
constructor
implicit-attempt
true
implicit
other
```

The second and third lines say explicit binding beats implicit binding: even though the
bound function is called as a property of an object, the write lands on `target`,
`otherTarget` stays unchanged. The fourth and fifth lines show constructor binding
beating explicit binding: called with `new`, the bound target is ignored, a new object
is used, and the chain is set up to the constructor's `prototype` object.

The order can be summarized in one sentence: **`new` > `bind`/`call`/`apply` > dot
operator > none.** There is a fifth case — functions that fit none of the rules and
have no `this` value of their own — and it will be covered two lessons from now.

## Summary

- The `this` value is determined by looking at how a function is called, not where it
  is defined.
- In default binding, `this` is `undefined` in strict mode and the global object in
  non-strict mode.
- In implicit binding, the object to the left of the dot operator is bound; only the
  last link counts.
- A method's bond breaks when it is assigned to a variable or passed as a callback;
  class methods are not exempt from this behavior.
- The prototype chain determines where a function will be found, `this` determines
  which data it operates on; the two are independent.
- Priority order: constructor binding, explicit binding, implicit binding, default
  binding.

## Next Step

In this lesson, explicit binding was introduced only as a rule; the differences among
the three operations that establish it were not covered. How do `call` and `apply` pass
arguments differently, why does `bind` produce a permanent bond, and how do these
operations lend a method not in an object's chain to that object? The next lesson
examines these three operations and the function-borrowing pattern.
