catname: "Tom"hi: ƒ hidogname: "Rex"hi: ƒ hifunction hithis1"use strict";2function hi() { return "I am " + this.name; }3const cat = { name: "Tom", hi };4const dog = { name: "Rex", hi };5console.log(cat.hi());6console.log(dog.hi());7const f = cat.hi;8console.log(f.call(dog));9const g = f.bind(cat);10console.log(g());11f();fgConsoleI am Tomthis.js:5I am Rexthis.js:6I am Rexthis.js:8I am Tomthis.js:10✕ TypeErrorthis.js:2this ?ƒƒcatdogcatundefinedTypeError"Tom""Rex"I am TomI am Rex
Back: the objects cat and dog, the function hi and the this box of the running callFront: the script this.js, the variables f and g, and the consoleTokens: what this is on each call, the name hi reads, and what it returnsAt the back, the objects cat and dog, and the one function hi with the this box of the call that is running. In front, the script this.js, the variables f and g, and the console. On every call a tag hops into the this box: the object before the dot, the argument of call, the object locked by bind, or undefined for a plain call. Then hi reads this.name and its answer goes to the console. The boxes are a simplification: cat, dog, f and g are bindings that refer to objects, and the this box stands for the this binding that each call gets. hi exists once; cat.hi, dog.hi and f all refer to it.

this is set by the call

  1. Inside a normal function, this is a hidden value the function receives every time it is called. It is not fixed where the function is written. How you call the function decides what this is.

One function, two objects

Four ways to call it

The rules

What happens

// step 1/11 · rule
this     a hidden value inside a function
set      each time the function is CALLED
not set  where the function is written
so       one function can see a different
         this on every call

Without "use strict", a plain call like f() sets this to the global object (globalThis, which is window in a browser), so f() would not throw: it would read the global object's name instead. Code inside a class or a module (<script type="module">) is always strict. Arrow functions, such as () => this.name, have no this of their own. They see the this of the code around them, and call, apply and bind cannot change it. That is why arrows are handy for callbacks inside methods.