Mastering JavaScript’s this: When, Why, and How It Changes
This article provides a comprehensive, step‑by‑step explanation of JavaScript’s this binding, covering execution context, global and function scopes, strict mode nuances, call/apply usage, and constructor behavior, all illustrated with clear diagrams and code examples.
When learning JavaScript, we often form vague or inaccurate conclusions about concepts like
this, which then spread online and cause confusion.
One common misconception is “whoever calls a function,
thispoints to that caller.” This works in some cases but fails in many, leading to puzzling bugs.
Search results on Baidu often contain incorrect knowledge that misleads developers for a long time.
Therefore, a thorough article is needed to give a correct, complete understanding of
this. First, we review the execution context.
In previous posts I described the lifecycle of an execution context; the diagram below summarizes it.
During the creation phase, a variable object, a scope chain, and the
thisbinding are established. The crucial point is that
thisis determined when the function is called, i.e., when the execution context is created. Consequently, the same function can have different
thisvalues depending on how it is invoked.
Once
thisis fixed during execution, it cannot be changed.
1. this in the Global Object
In the global environment,
thispoints to the global object itself, which makes it relatively simple.
2. this in Functions
To feel the unpredictability of
thisinside functions, consider the following strange examples.
Conclusion: In a function context,
thisis provided by the caller. If the caller is an object that owns the function,
thispoints to that object; if the function is called independently,
thisis
undefined(or the global object in non‑strict mode).
For example:
fn()– independent call,
thisis
undefined.
window.fn()– the function belongs to
window, so
thispoints to
window.
In demo03,
obj.cuses
this.a + 20, but
obj.cis not a function, so the previous rule does not apply. The rule is:
When
objis declared globally, any use of
obj.chas
thisbound to the global object; when
objis declared inside a function,
thisis
undefined(or the global object in non‑strict mode).
In real development, this pattern is not recommended. Strict mode is essential; most modern codebases already use it, and ES6 defaults to strict mode.
Additional examples reinforce the distinction between a caller that owns the function and an independent call.
foo.getA()–
getAis owned by
foo, so
thispoints to
foo.
test()– independent call,
thisis
undefined(or
windowin non‑strict mode).
Further code modifications illustrate the same principle.
3. Using call and apply to Explicitly Set this
JavaScript provides
calland
applyto manually set the
thisbinding. Both methods belong to every function; the first argument is the object that should become
this.
Example:
fnis not a method of
obj, but
fn.call(obj)binds
thisinside
fnto
obj, allowing access to
obj.a.
The arguments after the first are passed to the target function:
callpasses them one by one, while
applypasses an array. This difference enables many useful scenarios:
1. Convert array‑like objects to true arrays
2. Flexibly modify the this binding
3. Implement inheritance
In a constructor like
Student,
Parent.call(this)copies the parent’s initialization code and ensures
thispoints to the new
Studentinstance.
4. Preserve this when passing functions between contexts
When a callback loses its original
this, we can store the reference in a variable, use
bind, or apply
call/applyto restore it.
Common solution: assign
var self = thisbefore entering the inner function, or use
Function.prototype.bind(available natively in ES5).
ES5’s built‑in
bindmethod achieves the same effect.
4. this in Constructors and Prototype Methods
When using
new, the process involves four steps:
1. Create a new empty object.
2. Bind the constructor’s
thisto that new object.
3. Execute the constructor code, adding properties and methods to the object.
4. Return the new object.
Thus, inside a constructor,
thisrefers to the newly created instance (e.g.,
p1).
For prototype methods, the rule is the same: the method’s
thispoints to the object that invoked it, such as
p1.getName()where
thisis
p1.
In summary, mastering the binding rules of
this, understanding strict mode, and leveraging
call,
apply, and
bindwill help you avoid common pitfalls and write more predictable JavaScript code.
Tencent IMWeb Frontend Team
IMWeb Frontend Community gathering frontend development enthusiasts. Follow us for refined live courses by top experts, cutting‑edge technical posts, and to sharpen your frontend skills.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.