Understanding the JavaScript "this" Keyword: From Basics to Deep Insights
This article demystifies JavaScript’s this keyword by covering its runtime binding rules in global, function, method, constructor, prototype, and arrow contexts, explaining strict‑mode differences, call/apply/bind usage, event‑handler behavior, and the underlying ECMAScript reference mechanics that determine its value.
The this keyword appears everywhere in front‑end code and is a favorite interview topic. This article revisits the concept, clarifies common misconceptions, and provides a thorough explanation from basic to advanced levels.
Basic Understanding of this
this refers to the ThisBinding of the current execution environment. Its value is determined at call time, not at creation time, giving it runtime binding characteristics.
In the global execution context, this points to the global object ( window in browsers, global in Node), regardless of strict or non‑strict mode.
Function Execution Context – Normal Function Call
Consider the following functions:
function aaa(){
console.log("aaa");
bbb();
}
function bbb(){
console.log("bbb");
ccc();
}
function ccc(){
console.log("ccc");
}
aaa();Here aaa is called in the global context, bbb inside aaa 's context, and ccc inside bbb 's context. The value of this inside a function depends on the object used to invoke the function.
Another example demonstrates this in a simple function:
var name = 'window';
var example = function(){
console.log(this.name);
}
example(); // 'window' in non‑strict modeIn non‑strict mode the function runs in the global context, so this points to window . In strict mode the same code throws because this becomes undefined :
'use strict'
var name = 'window';
var example = function(){
console.log(this.name);
}
example(); // error, this -> undefinedVariables declared with let or const are not attached to window , so even if this points to the global object, this.name will be undefined :
let name = 'window';
let example = function(){
console.log(this === window);
console.log(this.name);
}
example(); // true, undefinedMethod Call on an Object
var name = 'window';
var example = function(){
console.log(this.name);
}
var obj = {
name: 'objInnerFunc',
func: example,
sonfunc: {
name: 'objSonFunc',
func: example,
}
}
obj.func(); // 'objInnerFunc'
obj.sonfunc.func(); // 'objSonFunc'
// equivalent with call:
obj.func.call(obj);
obj.sonfunc.func.call(obj.sonfunc);If a method is extracted into a standalone variable, the call loses its object binding:
var anotherFunc = obj.func;
anotherFunc(); // non‑strict: this -> window, strict: this -> undefinedcall / apply / bind
These functions let you explicitly set the first argument as the this value. In non‑strict mode, passing undefined or null defaults to window . Primitive values are boxed (e.g., 1 becomes Number(1) ). call and apply differ only in how additional arguments are supplied; bind returns a new function with a permanently bound this , unless the bound function is used as a constructor.
Constructor Call
function Example(name){
this.name = name;
// return function f(){}; // ignored if a non‑object is returned
// return {};
}
var result = new Example('123');When new is used, a fresh object is created, this is bound to that object, and the object is returned unless the constructor explicitly returns another object.
Prototype‑Chain Call
Even when a method lives on the prototype, this still refers to the instance that invoked it.
Arrow Functions
Arrow functions have no own this ; they inherit it from the surrounding (non‑arrow) lexical scope. Consequently they cannot be used as constructors and cannot be bound with call / apply / bind .
var name = 'window';
var example = {
name: '啦啦啦',
inner: function(){
var arrowDoSth = () => {
console.log(this.name);
}
arrowDoSth(); // '啦啦啦'
},
arrowDoSth2: () => {
console.log(this.name);
}
}
example.inner(); // '啦啦啦'
example.arrowDoSth2(); // 'window'Because arrowDoSth2 is an arrow function defined at the top level, it inherits this from the global scope, resulting in window .
DOM Event Handlers and jQuery
In standard event handlers, this points to the element that received the event. Older IE versions (IE6‑IE8) using attachEvent bind this to the global object.
Anonymous Functions
In strict mode, this inside an anonymous function is undefined ; otherwise it defaults to the global object.
Deep Understanding of this
ECMAScript distinguishes between language types (the seven primitive types) and specification types (Reference, List, Completion, Property Descriptor, etc.). The Reference type is most relevant to this . A Reference consists of:
base value – the object or EnvironmentRecord where the property resides
referenced name – the property name
strict reference flag
When a function is called, the engine computes a MemberExpression, obtains a Reference, and then determines this as follows:
Evaluate the MemberExpression to produce a Reference ( ref ).
If ref is a Reference, this is set to ref.base .
If not a Reference, strict mode yields undefined ; non‑strict mode yields the global object.
Examples (strict mode):
'use strict'
var value = 1;
var aaa = {
value: 2,
test: function () {
return this.value;
}
}
// 1. aaa.test() -> this = aaa, returns 2
console.log(aaa.test());
// 2. (aaa.test)() -> same as above
console.log((aaa.test)());
// 3. (aaa.test = aaa.test)() -> assignment returns a value, not a Reference, this = undefined
console.log((aaa.test = aaa.test)());
// 4. (false || aaa.test)() -> logical OR forces value retrieval, this = undefined
console.log((false || aaa.test)());
// 5. (aaa.test, aaa.test)() -> comma operator also retrieves value, this = undefined
console.log((aaa.test, aaa.test)());Thus, only when the call expression yields a Reference does this bind to the base object; otherwise it falls back to undefined (strict) or the global object (non‑strict).
Another common case is a globally defined function:
function test(){
console.log(this);
}
test(); // non‑strict: window, strict: undefinedIn the specification, the function’s Reference has an EnvironmentRecord as its base. In non‑strict mode the implicit this value is the global object; in strict mode it is undefined .
Understanding these low‑level mechanisms helps explain seemingly paradoxical behaviours such as (false || aaa.test)() returning 1 instead of the object's property.
References
https://juejin.cn/post/6844903746984476686
https://github.com/mqyqingfeng/Blog/issues/7
37 Interactive Technology Team
37 Interactive Technology Center
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.