patternjavascriptCritical
How does the "this" keyword work, and when should it be used?
Viewed 0 times
howshouldandusedthedoeswhenthiskeywordwork
Problem
I am looking to find a clear explanation of what the "this" keyword does, and how to use it correctly.
It seems to behave strangely, and I don't fully understand why.
How does
It seems to behave strangely, and I don't fully understand why.
How does
this work and when should it be used?Solution
this is a keyword in JavaScript that is a property of an execution context. Its main use is in functions and constructors.The rules for
this are quite simple (if you stick to best practices).Technical description of
this in the specificationThe ECMAScript standard defines
this via the abstract operation (abbreviated AO) ResolveThisBinding:The [AO] ResolveThisBinding […] determines the binding of the keyword
this using the LexicalEnvironment of the running execution context. [Steps]:- Let envRec be GetThisEnvironment().
- Return ? envRec.GetThisBinding().
Global Environment Records, module Environment Records, and function Environment Records each have their own GetThisBinding method.
The GetThisEnvironment AO finds the current running execution context’s LexicalEnvironment and finds the closest ascendant Environment Record (by iteratively accessing their [[OuterEnv]] properties) which has a this binding (i.e. HasThisBinding returns true). This process ends in one of the three Environment Record types.
The value of
this often depends on whether code is in strict mode.The return value of GetThisBinding reflects the value of
this of the current execution context, so whenever a new execution context is established, this resolves to a distinct value. This can also happen when the current execution context is modified. The following subsections list the five cases where this can happen.You can put the code samples in the AST explorer to follow along with specification details.
- Global execution context in scripts
This is script code evaluated at the top level, e.g. directly inside a `
:
// Global context
console.log(this); // Logs global object.
setTimeout(function(){
console.log("Not global context");
});
When in the initial global execution context of a script, evaluating this causes GetThisBinding to take the following steps:
The GetThisBinding concrete method of a global Environment Record envRec […] [does this]:
- Return envRec.[[GlobalThisValue]].
The [[GlobalThisValue]] property of a global Environment Record is always set to the host-defined global object, which is reachable via globalThis (window on Web, global on Node.js; Docs on MDN). Follow the steps of InitializeHostDefinedRealm to learn how the [[GlobalThisValue]] property comes to be.
- Global execution context in modules
Modules have been introduced in ECMAScript 2015.
This applies to modules, e.g. when directly inside a , as opposed to a simple .
When in the initial global execution context of a module, evaluating this causes GetThisBinding to take the following steps:
The GetThisBinding concrete method of a module Environment Record […] [does this]:
- Return undefined.
In modules, the value of this is always undefined in the global context. Modules are implicitly in strict mode.
- Entering eval code
There are two kinds of eval calls: direct and indirect. This distinction exists since the ECMAScript 5th edition.
- A direct
eval call usually looks like eval(…); or (eval)(…); (or ((eval))(…);, etc.).1 It’s only direct if the call expression fits a narrow pattern.2
- An indirect
eval call involves calling the function reference eval in any other way. It could be eval?.(…), (…, eval)(…), window.eval(…), eval.call(…,…), etc. Given const aliasEval1 = eval; window.aliasEval2 = eval;, it would also be aliasEval1(…), aliasEval2(…). Separately, given const originalEval = eval; window.eval = (x) => originalEval(x);, calling eval(…) would also be indirect.
See chuckj’s answer to “(1, eval)('this') vs eval('this') in JavaScript?” and Dmitry Soshnikov’s ECMA-262-5 in detail – Chapter 2: Strict Mode (archived) for when you might use an indirect eval() call.
PerformEval executes the eval code. It creates a new declarative Environment Record as its LexicalEnvironment, which is where GetThisEnvironment gets the this value from.
Then, if this appears in eval code, the GetThisBinding method of the Environment Record found by GetThisEnvironment is called and its value returned.
And the created declarative Environment Record depends on whether the eval call was direct or indirect:
- In a direct eval, it will be based on the current running execution context’s LexicalEnvironment.
- In an indirect eval, it will be based on the [[GlobalEnv]] property (a global Environment Record) of the Realm Record which executed the indirect eval.
Which means:
- In a direct eval, the
this value doesn’t change; it’s taken from the lexical scope that called eval.
- In an indirect eval, the
this value is the global object (globalThis).
What about new Function? — new Function is similar to eval`, but it doesn’t call the code immediately; it creates a function. A this binding doesn’t apply anywhere here, except when the function is called, which works normally, as explained in the next subsection.- Entering function code
En
Context
Stack Overflow Q#3127429, score: 1506
Revisions (0)
No revisions yet.