Every function is an object with a name, a length (declared parameters) and toString(), which returns its exact source. A regular function's this depends on how it is called. call(thisArg, a, b) and apply(thisArg, [a, b]) call it with a chosen this; bind(thisArg, a) returns a new function with this and leading arguments fixed (partial application).
| Call form | Value of this |
|---|---|
| obj.method() | obj |
| fn() | undefined in strict mode, globalThis in sloppy mode |
| fn.call(o), fn.apply(o), fn.bind(o) | o |
| new Fn() | the newly created object |
| arrow function | the enclosing scope's this, unchangeable |
"use strict";
function describe(greeting) { return `${greeting}, ${this?.name}`; }
const lion = { name: "King" };
const hiKing = describe.bind(lion, "Hi"); // this and first argument fixed
console.log(describe.call(lion, "Hey"), describe.apply(lion, ["Yo"]), hiKing(), describe("Plain"));
const counter = {
count: 0,
later() { setTimeout(() => console.log("arrow sees", ++this.count, hiKing.name), 0); },
};
counter.later();Output
Hey, King Yo, King Hi, King Plain, undefined arrow sees 1 bound describe
A method passed as a callback loses its object; fix it with bind() or an arrow. Prefer rest parameters to the legacy arguments object.