cf.completefrontendCode editorOpen lab
THE JAVASCRIPT FIELD GUIDE

The this keyword

Learn how JavaScript decides this from the call site: default, implicit, explicit, and new binding, their precedence, and strict-mode edge cases.

By the end, you can
  • 01
    Read the call siteFind the expression that decides this, not the place where the function was written.
  • 02
    Name the winning rulePredict default, implicit, explicit, bound, and new binding, including precedence.
  • 03
    Handle strict-mode edgesExplain why plain calls become undefined in strict mode and how primitives behave.

The call-site idea

this is JavaScript’s way for a regular function to ask, “Who am I working for in this call?” You already saw the friendly version in Methods & this: in user.sayHi(), this is usually the object before the dot. This lesson turns that intuition into the complete set of rules.

The key phrase is call site. Do not start by looking where the function was written. Start where it is called. The same function can have a different this five lines later if the call shape changes.

One-line definition

For a regular function, this is chosen by the call site: default, implicit, explicit, or new binding, with a fixed precedence when rules compete.

Real-life analogythis is like the word “my”

If Ada says “my laptop,” my means Ada’s laptop. If Grace says the exact same sentence, my means Grace’s laptop. The sentence did not change; the speaker did. this is that kind of word. Its meaning comes from who is “speaking” at the moment the function is called.

In real life: “My notebook” depends on who says it
In JavaScript: this.label depends on who called the function
In real life: A speaker at a microphone
In JavaScript: The call site gives a function its receiver
In real life: Moving the sentence to another room does not change “my”
In JavaScript: Where a regular function is written does not choose this

Where the analogy stops: The analogy stops with arrow functions: arrows do not take the microphone at all. They inherit this from the surrounding code, which is the next lesson.

We will use regular functions throughout. Arrow functions are special: they have no own this, so the four rules below do not apply to them. Keep that thought for Arrow functions & lexical this.

Call-site rules: read the call, not the function

INTERACTIVE

A call site is the exact expression that invokes the function: fn(), obj.fn(), fn.call(obj), or new Fn(). JavaScript looks at that expression and chooses this before the function body runs.

Try the trainer. Each row uses real JavaScript. The source uses inline methods or module-level objects so production minification cannot accidentally detach a method while shrinking the code.

Who is this? call-site trainer
Step 0 of 2Ready
Your turn: follow the blue line

Pick a call shape. Then step once to identify the call site, and again to see the this value that real JavaScript used.

Running in
  1. script
Next: line 7
Click the blue line to take the next stepPop out in the code editor (opens in a new tab)JavaScript
const ada = {  label: "Ada",  whoAmI() {    return this.label;  },};
CallStoreChangeResultRun = next line. Ran = already executed.
Recent returnsNothing yet. Start with the blue line.
Choose one visible call shape.

Changing the shape resets the replay. Predict the rule before stepping.

A guided replay recorded from real JavaScript calls, not an engine debugger. Step follows executed statements; Back reviews a snapshot. Reset starts a fresh run.

Notice two details professionals rely on. First, building.room.whoAmI() uses building.room as this, not building. Second, once you store a method in a plain variable and call fn(), the dot is gone. That is a new call site.

Recorded call-shape answers
Selected call shapePop out in the code editor (opens in a new tab)JavaScript
const ada = {  label: "Ada",  whoAmI() {    return this.label;  },};ada.whoAmI();
Real resultimplicit binding
Returned
Ada
this label
Ada
Why
The call site is `ada.whoAmI()`. The object immediately before the dot, `ada`, becomes `this`.
Try it yourself

Real JavaScript returned Ada. The rule is implicit binding, so this is Ada.

These rows are not guesses. The lesson tests run the same sources, including sloppy-mode rows in a vm script.

Default, implicit, explicit & new binding

RULE TABLE

The four regular-function rules are easier to remember if you imagine four ways someone can be “speaking.” Nobody in particular speaks in a plain call. An object speaks in a method call. call, apply, and bind hand the microphone to a chosen value. new builds a brand-new speaker.

The four call-site rules for this
RuleHow to recognize itWhat this becomesStrict-mode note
DefaultA plain call like fn()undefined in strict code; globalThis in sloppy scriptsStrict mode changes this rule the most
ImplicitA property call like obj.fn()The object immediately before the dot/bracketsSame in strict and sloppy mode
Explicitfn.call(obj), fn.apply(obj), or a bound functionThe value supplied explicitly; bound functions remember itStrict mode keeps primitive receivers primitive
newnew Fn()A fresh object linked to Fn.prototypeConstructors run with a new this; classes are strict
Real-life analogyFour ways to hold the microphone

Think of the function as a script to read aloud. The call site tells us who holds the microphone. A plain call has no speaker. A method call gives it to the object. call and friends hand it over explicitly. new creates a new speaker before the script starts.

In real life: No one is holding it
In JavaScript: Default binding: fn()
In real life: The owner picks it up
In JavaScript: Implicit binding: obj.fn()
In real life: Someone hands it to Grace
In JavaScript: Explicit binding: fn.call(grace)
In real life: A new speaker is built for the speech
In JavaScript: New binding: new Fn()

Where the analogy stops: Real microphones do not have a strict-mode switch, and they cannot box primitives. JavaScript can, so use the table for the exact edge cases.

Which binding rule?
  • whoAmI()
  • ada.whoAmI()
  • team.lead.whoAmI()
  • whoAmI.call(grace)
  • bound.call(other)
  • new Reporter()
  • new BoundReporter()
  • const fn = ada.whoAmI; fn()
Try it yourself
0 of 8 correct

Sort each call shape into the rule that chooses this.

Choose a category for every card. You can change an answer at any time; Reset clears them all.

Explicit binding is big enough to get the next lesson, call, apply & bind. For now, know the family: call invokes with individual arguments, apply invokes with an array of arguments, and bind returns a new function that remembers its receiver.

Binding precedence: when rules compete

STEP THROUGH

Most call sites match one rule. A few deliberately combine them. Then JavaScript uses precedence: new beats bound, bound beats later call/apply, call/apply beats implicit, implicit beats default.

Binding precedence: who wins?
Step 0 of 6Ready
Your turn: follow the blue line

When call-site rules compete, use this order: new, then bound, then call/apply, then implicit, then default.

Running in
  1. script
Next: line 15
Click the blue line to take the next stepPop out in the code editor (opens in a new tab)JavaScript
function show() {  "use strict";  return this.label;}function Reporter() {  this.label = "new reporter";}Reporter.prototype.show = show; const ada = { label: "Ada", show };const grace = { label: "Grace" };const bound = show.bind({ label: "Bound target" });const BoundReporter = Reporter.bind({ label: "Bound target" }); bound.call(grace);new BoundReporter().show();
CallStoreChangeResultRun = next line. Ran = already executed.
Recent returnsNothing yet. Start with the blue line.
A guided replay recorded from real JavaScript calls, not an engine debugger. Step follows executed statements; Back reviews a snapshot. Reset starts a fresh run.

Read the three results as a ladder. ada.show.call(grace) starts with a method lookup, but call(grace) wins. bound.call(grace) tries to replace a bound receiver, but bound functions keep the earlier value. new BoundReporter() still constructs a fresh object; new wins for constructor calls.

Precedence shortcut

Ask the strongest question first: “Is there new?” Then “Is it already bound?” Then “Did this call use call or apply?” Then “Is there an object before the dot?” If all answers are no, default binding is left.

this in strict mode

REAL OUTPUT

Strict mode does not rewrite the whole this system. It changes two important edges: default binding and primitive receivers. In strict mode a plain call gets undefined; a sloppy classic script substitutes globalThis. In strict mode, call(5) keeps the primitive number; sloppy mode boxes it as a Number object.

Strict mode vs sloppy mode
Step 0 of 4Ready
Your turn: follow the blue line

Strict mode does not change implicit, explicit, or new binding. It changes default binding and primitive receiver boxing.

Running in
  1. script
Next: line 16
Click the blue line to take the next stepPop out in the code editor (opens in a new tab)JavaScript
function strictPlain() {  "use strict";  return this;}function sloppyPlain() {  return this;}function strictNumber() {  "use strict";  return typeof this;}function sloppyNumber() {  return typeof this;} console.log(sloppyPlain() === globalThis);console.log(strictNumber.call(5));console.log(sloppyNumber.call(5));
CallStoreChangeResultRun = next line. Ran = already executed.
Recent returnsNothing yet. Start with the blue line.
A guided replay recorded from real JavaScript calls, not an engine debugger. Step follows executed statements; Back reviews a snapshot. Reset starts a fresh run.
Classic script proof
Sandboxed classic scriptPop out in the code editor (opens in a new tab)HTML
<!doctype html><meta charset="utf-8"><script>function plain() { return this === globalThis; }function primitive() { return typeof this; }parent.postMessage({ kind: "this-keyword-sloppy", plain: plain(), primitive: primitive.call(5) }, "*");</script>
iframe resultsloppy script

Waiting for the sandboxed classic script…

Try it yourself
Sandbox reruns on reset.

Waiting for the sandboxed classic script…

The iframe is sandboxed with scripts only and runs predefined classic-script code, not learner input.
Strict vs sloppy behavior for default and primitive receivers
CallStrict modeSloppy script
plain()this is undefinedthis is globalThis
plain.call(null)this is nullthis becomes globalThis
plain.call(5)this is the number primitivethis is a boxed Number object
Module or class bodyAlways strictNot applicable inside modules/classes

This site’s components are ES modules, and modules are always strict. Class bodies are always strict too. That is why sloppy default binding is shown as a recorded and tested classic-script fact, not as code the lesson module can directly run during render.

Where you’ll use this

You will meet this in object APIs, classes, array methods, event handlers, and library utilities. Here are the patterns to keep nearby.

Detached method fixPop out in the code editor (opens in a new tab)JavaScript
const user = {  label: "Ada",  getLabel() { return this.label; },};const getLabel = user.getLabel;console.log(getLabel.call(user));

The method was detached into getLabel. Calling getLabel() would be default binding. Calling getLabel.call(user) borrows the method with the right receiver. You will go deeper on this in Losing this.

Borrow a methodPop out in the code editor (opens in a new tab)JavaScript
const cartLike = { 0: "book", 1: "pen", length: 2 };const joined = Array.prototype.join.call(cartLike, " + ");console.log(joined);

Method borrowing is practical: array methods can work on array-like objects when their this has numeric keys and a length. Some callbacks also accept a thisArg, such as array.forEach(fn, thisArg). Browser event listeners have their own rule: a regular function listener usually receives the element as this. The arrow-function lesson explains why arrows ignore that and keep lexical this instead.

Common misconceptions

  • “this means the function’s object.” Only at an implicit call site like obj.fn(). Detached calls lose that object.
  • “Nested objects make the outer object this.” The receiver is the object immediately before the final property access.
  • “bind can be overridden with call.” A bound function remembers its receiver; later call cannot change it.
  • “Strict mode breaks methods.” Strict mode changes plain calls and primitive boxing. Normal method calls still use the object before the dot.
  • “Arrow functions follow these four rules.” Arrows have no own this; they close over the surrounding one.

Practice exercises

5 EXERCISES
Exercise 1 · Warm-upPredict an implicit call and a detached call

Type the two printed lines in order.

Starter codePop out in the code editor (opens in a new tab)JavaScript
"use strict";
function show() { return this?.label ?? String(this); }
const ada = { label: "Ada", show };
const fn = ada.show;
console.log(ada.show());
console.log(fn());

Answer, then press Check. Spacing and letter case don’t matter.

    Exercise 2 · PracticeFix a detached method

    Change the call so the detached method still reads from user.

    Starter codePop out in the code editor (opens in a new tab)JavaScript
    const user = {
      label: "Ada",
      getLabel() { return this.label; },
    };
    const getLabel = user.getLabel;
    console.log(getLabel.call(user));

    Answer, then press Check. Spacing and letter case don’t matter.

      Exercise 3 · PracticeBorrow an array method

      Use call to join an array-like object.

      Starter codePop out in the code editor (opens in a new tab)JavaScript
      const cartLike = { 0: "book", 1: "pen", length: 2 };
      const joined = Array.prototype.join.call(cartLike, " + ");
      console.log(joined);

      Answer, then press Check. Spacing and letter case don’t matter.

        Exercise 4 · ChallengePredict new vs bind

        Which label wins when a bound constructor is called with new?

        Starter codePop out in the code editor (opens in a new tab)JavaScript
        function Reporter() { this.label = "new reporter"; }
        Reporter.prototype.show = function show() { return this.label; };
        const BoundReporter = Reporter.bind({ label: "bound target" });
        console.log(new BoundReporter().show());

        Answer, then press Check. Spacing and letter case don’t matter.

          Exercise 5 · ChallengeExplain strict vs sloppy default binding

          Type the two booleans printed by the comparisons.

          Starter codePop out in the code editor (opens in a new tab)JavaScript
          function strictPlain() { "use strict"; return this; }
          function sloppyPlain() { return this; }
          console.log(strictPlain() === undefined);
          console.log(sloppyPlain() === globalThis);

          Answer, then press Check. Spacing and letter case don’t matter.

            Check your understanding

            7 QUESTIONS
            Lesson quiz · 7 questionsScore: first tries count
            1. Question 1 of 7What decides the value of this for a regular function call?

              Choose an answer to see the explanation.

            2. Question 2 of 7What does the detached strict call print?

              Read the code, then predictPop out in the code editor (opens in a new tab)JavaScript
              "use strict";
              function show() { return this?.label ?? String(this); }
              const ada = { label: "Ada", show };
              const fn = ada.show;
              console.log(fn());

              Choose an answer to see the explanation.

            3. Question 3 of 7Which rule applies to profile.name.toUpperCase.call(other) for the toUpperCase call?

              Choose an answer to see the explanation.

            4. Question 4 of 7What does the bound constructor print?

              Read the code, then predictPop out in the code editor (opens in a new tab)JavaScript
              function Reporter() { this.label = "new reporter"; }
              Reporter.prototype.show = function show() { return this.label; };
              const BoundReporter = Reporter.bind({ label: "bound target" });
              console.log(new BoundReporter().show());

              Choose an answer to see the explanation.

            5. Question 5 of 7In strict mode, what is this inside a plain function call fn()?

              Choose an answer to see the explanation.

            6. Question 6 of 7What does this print?

              Read the code, then predictPop out in the code editor (opens in a new tab)JavaScript
              function show() { "use strict"; return typeof this; }
              console.log(show.call(5));

              Choose an answer to see the explanation.

            7. Question 7 of 7Which precedence order is correct, from strongest to weakest?

              Choose an answer to see the explanation.

            Key takeaways

            • Regular-function this is decided at the call site.
            • The four rules are default, implicit, explicit, and new binding.
            • Precedence is new, bound, call/apply, implicit, then default.
            • Strict mode makes plain-call this be undefined and keeps primitive receivers primitive.
            • Arrow functions are different: they have lexical this.

            Final definition: this is the receiver a regular function gets from how it is called, unless an arrow function inherited it earlier.

            Up next: call, apply & bind.

            CompleteFrontend Clear concepts. Working examples.