this in JavaScript according to official specification
Published April 25, 2025Understanding this in JavaScript
The behavior of this in JavaScript can be confusing, but it’s critical to understand how it works in different contexts. This article breaks down how this behaves in various environments, such as the global scope, normal functions, arrow functions, and when invoked through different mechanisms like call, apply, bind, or the new operator.
Before We Dive In
To understand how this works, we need to grasp two key concepts about JavaScript execution:
- JavaScript code execution always involves running a function.
- Execution happens in two stages:
- Creating the function’s surrounding environment (context).
- Executing the function’s code.
Information: These stages are critical because the value of
thisis determined at the moment a function is called, based on how it’s invoked.
Important Definitions
Here are the core definitions to understand this in JavaScript:
thisis not the context itself but a special identifier (variable) defined locally for all "normal" functions.- By default,
thisisundefinedin strict mode or the global object in non-strict (sloppy) mode. - The value of
thiscan only be set at the moment of a function’s invocation, depending on the form and method of the call. - External APIs can bind
thisto any value, depending on the API author’s needs.
Additional Definitions
What is a "Normal Function"?
A normal function is any function that is not an arrow function. This distinction is important because arrow functions handle this differently.
What is Dot Notation?
Dot notation refers to the syntax where two identifiers are separated by a dot, e.g., theObj.theProperty. For function calls, it looks like theObj.doThing() or theObj["doThing"](), which are equivalent.
Tip: Understanding dot notation is key when analyzing
thisin method calls, as it directly affects whatthisis refers to.
this in the Global Environment
How do we determine the value of this in the global environment?
-
Identify whether
thisis accessed in a script or a module. -
The value of
thisdepends on the host system (e.g., browser or Node.js). -
In Node.js,
thisin the global scope is an empty object. -
In browsers,
thisis typically the global object (window). -
According to the JavaScript specification,
thisin the global environment can be anything, depending on the host.
this in a Module Script
'use strict'; // Global module scope console.log(this, 'this in module'); // Result: undefined
Let’s answer the following questions:
- Are we inside a function? No.
- Are we in the global environment? Yes.
- Is it a module? Yes.
- In this case,
thisisundefined.
this in a Default Script
'use strict'; // Global default scope console.log(this, 'this in script'); // Result: global object (window in browsers)
Let’s answer the following questions:
- Are we inside a function? No.
- Are we in the global environment? Yes.
- Is it a module? No.
- Is it a default script? Yes.
- In this case,
thisequals the global object (e.g.,windowin browsers).
Warning: The value of
thisin the global scope depends on the host environment. If the host modifiesthis, it will differ from the default global object.
this in Normal Functions
To determine what this is inside a normal function, we must examine how the function is called. Let’s explore different invocation methods.
Direct Function Call
'use strict'; function doThing() { console.log(this, 'this in function'); } doThing(); // Result: undefined
Let’s answer the following questions:
- Are we inside a function? Yes.
- Is it an arrow function? No.
- Is it called via
call,apply, or transformed bybind? No. - Is it called via the
newoperator? No. - Is it called via dot notation? No.
- Is it called via an external API? No.
- In this case,
thisisundefined(in strict mode).
Using call, apply, or bind
When a function is invoked with call, apply, or bind, this is set to the value passed to these methods.
'use strict'; function doThing(arg) { console.log(this, `this in function with ${arg}`); console.log('I am new this value' === this); // true } const newThisValue = 'I am new this value'; doThing.call(newThisValue, 'call'); doThing.apply(newThisValue, ['apply']); doThing.bind(newThisValue, 'bind')();
Let’s answer the following questions:
- Are we inside a function? Yes.
- Is it an arrow function? No.
- Is it called via
call,apply, orbind? Yes. - In this case,
thisequals the value passed tocall,apply, orbind(here,newThisValue).
Using the new Operator
When a function is invoked with the new operator, this is bound to a new empty object (unless explicitly set inside the function).
'use strict'; function doThing() { console.log(this, 'this in function called by new operator'); console.log(this instanceof Object && Object.keys(this).length === 0); // true } new doThing();
Let’s answer the following questions:
- Are we inside a function? Yes.
- Is it an arrow function? No.
- Is it called via
call,apply, orbind? No. - Is it called via the
newoperator? Yes. - In this case,
thisis a new empty object.
Warning: Not all functions can be invoked with
new. Only functions with an internal[[Construct]]method can be used as constructors. Arrow functions, bound functions, and object methods lack this method and will throw aTypeError.
'use strict'; function doThing() { console.log('bind'); } const arrowFunction = () => console.log('arrow'); const obj = { shortMethod() { console.log('shortMethod'); } }; new doThing.bind(undefined); // TypeError: is not a constructor new arrowFunction; // TypeError: is not a constructor new obj.shortMethod; // TypeError: is not a constructor
Using Dot Notation
When a function is called via dot notation, this is bound to the identifier before the dot.
'use strict'; function doThing() { console.log('dot notation', this); console.log('doThing' in this); // true } const obj = {}; obj.doThing = doThing; obj.doThing(); // or obj["doThing"]()
Let’s answer the following questions:
- Are we inside a function? Yes.
- Is it an arrow function? No.
- Is it called via
call,apply, orbind? No. - Is it called via the
newoperator? No. - Is it called via dot notation? Yes.
- In this case,
thisequals the identifier before the dot (here,obj).
Using External APIs
When a function is passed to an external API (e.g., setTimeout), the value of this depends on the API’s implementation.
'use strict'; function doThing() { console.log('timeout', this); } setTimeout(doThing, 1); // In browsers: window; In Node.js: Timeout class
Let’s answer the following questions:
- Are we inside a function? Yes.
- Is it an arrow function? No.
- Is it called via
call,apply, orbind? No. - Is it called via the
newoperator? No. - Is it called via dot notation? No.
- Is it called via an external API? Yes.
- In this case,
thisdepends on the API’s documentation (e.g.,windowin browsers,Timeoutin Node.js).
Tip: Always check the documentation of the external API to understand how it binds
this. Without explicitcall,apply, orbind, the value can vary.
this in Arrow Functions
Arrow functions do not have their own this. Instead, they inherit this from their parent lexical environment.
'use strict'; function doThing() { (() => console.log('arrow inside', this))(); } doThing(); // Result: undefined
Let’s answer the following questions:
- Are we inside a function? Yes.
- Is it an arrow function? Yes.
- Is the parent environment a normal function? Yes.
- In this case,
thisis inherited from the parent function’sthis(here,undefinedbecausedoThingwas called directly).
Information: Arrow functions are powerful for preserving the
thisvalue from their surrounding scope, but this behavior can be confusing if you expect them to behave like normal functions.
Final Thoughts
Understanding this in JavaScript requires careful attention to how and where a function is called. Whether in the global environment, normal functions, or arrow functions, the value of this is determined by specific rules tied to the invocation method. By mastering these rules, you can avoid common pitfalls and write more predictable code.
Special thanks to the content creator “Demi Murych” for shedding light on JavaScript’s intricacies through their YouTube channel As For JS. Their work inspired this article and helps developers navigate the complexities of the language.
Dmytro Notes