Originally published on php-to-js.learnio.dev — part of the PHP to JavaScript course. View this lesson on the original site.
Regular functions get this from how they are called
PHP methods always have $this when called on an object. JavaScript regular functions choose this at the call site — four common patterns, one of which bites PHP developers most often.
PHP habit
<?php
class Invoice {
public function total(): int {
return 100;
}
}
$invoice = new Invoice();
$invoice->total(); // $this is always $invoice
JavaScript equivalent: four bindings
// 1. Default — standalone call (strict: undefined)
function show() {
console.log(this);
}
show();
// 2. Implicit — method call
const invoice = {
total() {
return 100;
},
};
invoice.total(); // this === invoice
// 3. Explicit — call/apply
show.call({ label: 'explicit' });
// 4. new — constructor (skip for now)
| Pattern | Example | this is |
|---|---|---|
| Default | fn() |
undefined in strict mode |
| Implicit | obj.fn() |
obj |
| Explicit | fn.call(ctx) |
ctx |
new |
new Fn() |
new object |
The PHP developer footgun
const invoice = { total() { return 100; } };
const fn = invoice.total;
fn(); // not 100 — lost implicit binding
Extracting a method drops the object. Fix with bind, wrapper arrow, or call as invoice.total().
const bound = invoice.total.bind(invoice);
bound(); // 100
Try it
Use the amber Try it panel below. Click Run.
const cart = {
items: [10, 20],
sum() {
return this.items.reduce((a, b) => a + b, 0);
},
};
console.log('method call', cart.sum());
const loose = cart.sum;
try {
console.log('detached', loose());
} catch (e) {
console.log('detached failed:', e.message);
}
console.log('bound', cart.sum.bind(cart)());
Method call works; detached fails or returns wrong; bind restores the object.
From PHP to JavaScript — Control Flow, Functions, and Scope