Problem
On the Stack Overflow site, I noted that there does not appear to be a clear explanation of what the this keyword is and how it is used appropriately (and erroneously) in JavaScript.
I’ve seen some odd behavior from it that I can’t explain.
When should this be utilized and how does it work?
Asked by Maxim Gershkovich
Solution #1
This is a JavaScript keyword that refers to a property of an execution context. Its primary applications are in functions and constructors. The rules are straightforward (if you stick to best practices).
The abstract operation is defined in the ECMAScript standard (abbreviated AO) ResolveThisBinding:
GetThisBinding methods exist for global Environment Records, module Environment Records, and function Environment Records.
The GetThisEnvironment AO looks up the LexicalEnvironment of the current running execution context and seeks the closest ascending Environment Record with this binding (by repeatedly accessing their [[OuterEnv]] attributes) (i.e. HasThisBinding returns true). This procedure results in one of the three types of Environment Records.
The importance of this is often determined by whether or not the code is in strict mode.
GetThisBinding’s return value reflects the current execution context’s value, hence this resolves to a different value everytime a new execution context is established. When the current execution context is changed, this can also happen. The five scenarios that can occur are listed in the subsections below.
You can use the AST explorer to follow along with the code examples and specification information.
This is script code that is evaluated at the top level, such as within a script>:
<script>
// Global context
console.log(this); // Logs global object.
setTimeout(function(){
console.log("Not global context");
});
</script>
When this is evaluated in the script’s initial global execution environment, GetThisBinding performs the following actions:
A global Environment Record’s [[GlobalThisValue]] property is always set to the host-defined global object, which can be accessed via globalThis (window on Web, global on Node.js; Docs on MDN). Learn how the [[GlobalThisValue]] property is created by following the steps in InitializeHostDefinedRealm.
In ECMAScript 2015, modules were introduced.
This is true for modules, such as when they are directly inside a script type=”module”> rather than a plain script>.
When this is evaluated in a module’s first global execution context, GetThisBinding performs the following actions:
In the global context, the value of this is always undefined in modules. Modules are in strict mode by default.
Direct and indirect eval calls are the two types of eval calls. This distinction has existed since the fifth edition of ECMAScript.
“(1, eval)(‘this’) vs eval(‘this’) in JavaScript?” is answered by chuckj. for when you might utilize an indirect eval() call, and Dmitry Soshnikov’s ECMA-262-5 in detail – Chapter 2: Strict Mode (archived).
The eval code is executed by PerformEval. As its LexicalEnvironment, it produces a new declarative Environment Record, from which GetThisEnvironment retrieves the this value.
The GetThisBinding method of the Environment Record obtained by GetThisEnvironment is then invoked and its value returned if this exists in eval code.
And whether the eval call was direct or indirect determines whether a declarative Environment Record is created:
Which means:
What about a new feature? — new Function is similar to eval, but instead of immediately calling the code, it generates a function. This binding has no effect here, except when the function is called, which works as expected, as explained in the next subsection.
Entering function code occurs when calling a function.
Invoking a function can be done in one of four ways.
The actual function call occurs at the Call AO, which is invoked with a context-dependent thisValue argument that is passed along in a long chain of call-related calls. The function’s [[Call]] internal slot is called by Call. This necessitates A new function Environment Record is generated in PrepareForOrdinaryCall:
In addition, there is the [[ThisValue]] field in a function Environment Record:
The [[ThisBindingStatus]] property of the function environment is also set by the NewFunctionEnvironment method.
OrdinaryCallBindThis is also called by [[Call]], where the suitable thisArgument is decided based on:
Once thisArgument has been found, a last call to the BindThisValue method of the newly formed function Environment Record binds the [[ThisValue]] field to the thisArgument.
Finally, a function Environment Record’s GetThisBinding AO takes the value for this from this field:
Again, the actual method for determining this value is dependent on a variety of circumstances; this was simply a high-level summary. Let’s look at all of the specific cases with this technical background in mind.
OrdinaryFunctionCreate sets the [[ThisMode]] internal slot of the function object to “lexical” when an arrow function is evaluated.
OrdinaryCallBindThis is a function that takes a function F:
This just indicates that the remainder of the algorithm that binds this is bypassed. This value is not bound by an arrow function.
So, what exactly is going on inside an arrow function? The HasThisBinding method explicitly returns false when compared to ResolveThisBinding and GetThisEnvironment.
As a result, the external world is examined iteratively. The procedure will come to a close in one of the three settings that have this binding.
This simply indicates that this originates from the lexical scope of the arrow function in arrow function bodies, or in other words (from Arrow function versus function declaration / expressions: Are they equivalent / interchangeable?):
This is controlled by how the function is invoked in conventional functions (functions, methods).
These “syntax variants” come in handy in this situation.
Consider the following object, which has a function:
const refObj = {
func: function(){
console.log(this);
}
};
Alternatively:
const refObj = {
func(){
console.log(this);
}
};
This value inside func will be refObj.1 in any of the following function calls.
If the called function is a syntactically a property of a base object, then this base will be the call’s “reference,” which in most circumstances will be the value of this. The evaluation stages referenced above clarify this; for example, the CallMemberExpression in refObj.func() (or refObj[“func”]()) is the whole expression refObj.func(), which consists of the MemberExpression refObj.func and the Arguments ().
However, refObj.func and refObj each have three functions:
refObj.func as a value is the callable function object; the corresponding reference is used to determine the this binding.
The optional chaining and tagged template examples function in a similar way: the reference is everything before the?.(), before the “, or before the “””””””””””””””””””” ().
EvaluateCall uses IsPropertyReference of that reference to determine if it is a property of an object, syntactically. It’s attempting to obtain the reference’s [[Base]] property (which is e.g. refObj, when applied to refObj.func; or foo.bar when applied to foo.bar.baz). If it is written as a property, then GetThisValue will get this [[Base]] property and use it as the this value.
Note that getters and setters behave similarly to methods in this regard. Simple attributes, such as this one, have no effect on the execution context; for example, this is in global scope:
const o = {
a: 1,
b: this.a, // Is `globalThis.a`.
[this.a]: 2 // Refers to `globalThis.a`.
};
A function that isn’t called as a property is normally called without a base reference. Consider the following scenario:
func(); // As opposed to `refObj.func();`.
When passing or assigning methods, or when using the comma operator, this also happens. This is where the distinction between a Reference Record and a Value comes into play.
You’ll note that function j can only return the function object (Value) itself, not a Reference Record, if you read the specification carefully. As a result, the base reference refObj is no longer available.
const g = (f) => f(); // No base ref.
const h = refObj.func;
const j = () => refObj.func;
g(refObj.func);
h(); // No base ref.
j()(); // No base ref.
(0, refObj.func)(); // Another common pattern to remove the base ref.
Calls to EvaluateCall Here, call with an undefined thisValue. In OrdinaryCallBind, this makes a difference. This (thisArgument: the thisValue supplied to Call) (F: the function object):
Note that step 5 in strict mode sets the real value of this to the given thisArgument — undefined in this case. An undefined or null thisArgument in “sloppy mode” causes this to be the global this value.
If IsPropertyReference returns false, EvaluateCall performs the following actions:
This is where an undefined thisValue may appear: except in with statements, refEnv.WithBaseObject() is always undefined. ThisValue will be the binding object in this situation.
To regulate the with binding behavior, there’s also Symbol.unscopables (Docs on MDN).
To recap everything we’ve learned thus far:
function f1(){
console.log(this);
}
function f2(){
console.log(this);
}
function f3(){
console.log(this);
}
const o = {
f1,
f2,
[Symbol.unscopables]: {
f2: true
}
};
f1(); // Logs `globalThis`.
with(o){
f1(); // Logs `o`.
f2(); // `f2` is unscopable, so this logs `globalThis`.
f3(); // `f3` is not on `o`, so this logs `globalThis`.
}
and:
"use strict";
function f(){
console.log(this);
}
f(); // Logs `undefined`.
// `with` statements are not allowed in strict-mode code.
It’s worth noting that it doesn’t matter where a normal function is defined when evaluating this.
Another result of OrdinaryCallBind step 5 is This, together with step 6.2 (6.b in the spec), means that in “sloppy” mode, a primitive’s value is only converted to an object.
Let’s take a look at another source for the this value: the three override methods for the this binding: 4
.bind creates a bound function with thisArg as its this binding, which cannot be changed. .call and.call are two terms that can be used interchangeably. apply Call the function right away, with thisArg as the binding.
.bind generates a bound function with BoundFunctionCreate, while.call and.apply map directly to Call, using the provided thisArg. These have their own [[Call]] method, which looks up the [[BoundThis]] internal slot of the function object.
Setting a custom this value can look like this:
function f(){
console.log(this);
}
const myObj = {},
g = f.bind(myObj),
h = (m) => m();
// All of these log `myObj`.
g();
f.bind(myObj)();
f.call(myObj);
h(g);
For objects, this is the same in strict and non-strict mode.
Now try to come up with a simple value:
function f(){
console.log(this);
}
const myString = "s",
g = f.bind(myString);
g(); // Logs `String { "s" }`.
f.call(myString); // Logs `String { "s" }`.
Primitives are coerced to their object-wrapped form in non-strict mode. When you call Object(“s”) or new String, you receive the same type of object (“s”). You can utilize primitives in strict mode:
"use strict";
function f(){
console.log(this);
}
const myString = "s",
g = f.bind(myString);
g(); // Logs `"s"`.
f.call(myString); // Logs `"s"`.
These methods are used by libraries, for example, jQuery sets this to the DOM element selected here:
$("button").click(function(){
console.log(this); // Logs the clicked button.
});
When employing the new operator to call a function as a constructor, EvaluateNew calls Construct, which calls the [[Construct]] method. ThisArgument is set to a new object constructed from the constructor’s prototype if the function is a base constructor (i.e. not a class extends……) The instance object will inherit any properties placed on this in the constructor. Unless you specifically return your own non-primitive value, this is implicitly returned.
In ECMAScript 2015, a class was added as a new way of generating constructor functions.
function Old(a){
this.p = a;
}
const o = new Old(1);
console.log(o); // Logs `Old { p: 1 }`.
class New{
constructor(a){
this.p = a;
}
}
const n = new New(1);
console.log(n); // Logs `New { p: 1 }`.
Class declarations are in strict mode by default:
class A{
m1(){
return this;
}
m2(){
const m1 = this.m1;
console.log(m1());
}
}
new A().m2(); // Logs `undefined`.
As previously indicated, class extends…… is an exception to the new behavior. Derived classes don’t set their this value right away when they’re called; it takes a succession of super calls to get to the base class (happens implicitly without an own constructor). It is not permitted to use this before invoking super.
The value of the lexical scope (the function Environment Record) of the call is passed to the super constructor when super is called. For super calls, GetThisValue has a particular rule. BindThisValue is used to connect this to that Environment Record.
class DerivedNew extends New{
constructor(a, a2){
// Using `this` before `super` results in a ReferenceError.
super(a);
this.p2 = a2;
}
}
const n2 = new DerivedNew(1, 2);
console.log(n2); // Logs `DerivedNew { p: 1, p2: 2 }`.
In ECMAScript 2022, instance fields and static fields were introduced.
ClassDefinitionEvaluation is called when a class is evaluated, and it modifies the current execution context. Each ClassElement has the following properties:
A PrivateEnvironment contains private fields (such as #x) and methods.
TC39 is currently working on a stage 3 proposal for static blocks. Static blocks are similar to static fields and methods in that they contain a reference to the class itself.
This works the same way in methods and getters / setters as it does in conventional function properties.
class Demo{
a = this;
b(){
return this;
}
static c = this;
static d(){
return this;
}
// Getters, setters, private modifiers are also possible.
}
const demo = new Demo;
console.log(demo.a, demo.b()); // Both log `demo`.
console.log(Demo.c, Demo.d()); // Both log `Demo`.
1: (o.f)() is the same as o.f(); (f)() is the same as f() (). This is detailed in this page on 2ality (archived). Look at how a ParenthesizedExpression is examined in particular.
2: It must be a MemberExpression, not a property, have the precise [[ReferencedName]] “eval,” and be the percent eval percent intrinsic object.
3: If the specification specifies, “Let ref be the result of evaluating X.”, then X is an expression for which the evaluation steps must be found. One of these algorithms, for example, is used to evaluate a MemberExpression or a CallExpression. Some of these lead to the creation of a Reference Record.
4: There are a number of other native and host methods that accept a thisArg as their second parameter, including Array.prototype.map, Array.prototype.forEach, and others. Anyone can change this by writing their own methods, such as (func, thisArg) => func.bind(thisArg), (func, thisArg) => func.call(thisArg), and so on. MDN, as usual, provides excellent documentation.
Answer the question “What is the value of this at the highlighted line?” for each code snippet. Why?”.
Click the gray boxes to reveal the answers.
Answered by 34 revs, 9 users 70%
Solution #2
In JavaScript, the this keyword acts differently than in other languages. The this keyword in Object Oriented languages refers to the current instance of the class. The value of this in JavaScript is determined by the function’s invocation context (context.function()) and where it is called.
1. When used in a broad sense
This is connected to a global object when used in a global context (window in browser)
document.write(this); //[object Window]
Because the function is truly made a global context method, when you use this inside a function declared in the global context, this is still connected to global object.
function f1()
{
return this;
}
document.write(f1()); //[object Window]
F1 has been turned into a global object method. As a result, we can call it on the window object as follows:
function f()
{
return this;
}
document.write(window.f()); //[object Window]
2. When used as part of an object method
This keyword is connected to the “immediate” enclosing object when used inside an object method.
var obj = {
name: "obj",
f: function () {
return this + ":" + this.name;
}
};
document.write(obj.f()); //[object Object]:obj
I’ve put the term “instant” in double quotes above. It’s to demonstrate that if you nest an object within another object, it’s bound to the parent object.
var obj = {
name: "obj1",
nestedobj: {
name:"nestedobj",
f: function () {
return this + ":" + this.name;
}
}
}
document.write(obj.nestedobj.f()); //[object Object]:nestedobj
Even if you explicitly add a function to the object as a method, it still follows the above constraints, pointing to the immediate parent object.
var obj1 = {
name: "obj1",
}
function returnName() {
return this + ":" + this.name;
}
obj1.f = returnName; //add method to object
document.write(obj1.f()); //[object Object]:obj1
3. When using a context-free function.
Even if the function is declared inside the object, it is tied to the global object (window in browser) when you use this inside function that is invoked without any context (i.e. not on any object).
var context = "global";
var obj = {
context: "object",
method: function () {
function f() {
var context = "function";
return this + ":" +this.context;
};
return f(); //invoked without context
}
};
document.write(obj.method()); //[object Window]:global
Trying everything out using functions
We can also use functions to test the above things. There are, nevertheless, some distinctions.
Below, I tried out all of the things we did with Object and this above, but instead of writing an object straight, I created a function first.
/*********************************************************************
1. When you add variable to the function using this keyword, it
gets added to the function prototype, thus allowing all function
instances to have their own copy of the variables added.
*********************************************************************/
function functionDef()
{
this.name = "ObjDefinition";
this.getName = function(){
return this+":"+this.name;
}
}
obj1 = new functionDef();
document.write(obj1.getName() + "<br />"); //[object Object]:ObjDefinition
/*********************************************************************
2. Members explicitly added to the function protorype also behave
as above: all function instances have their own copy of the
variable added.
*********************************************************************/
functionDef.prototype.version = 1;
functionDef.prototype.getVersion = function(){
return "v"+this.version; //see how this.version refers to the
//version variable added through
//prototype
}
document.write(obj1.getVersion() + "<br />"); //v1
/*********************************************************************
3. Illustrating that the function variables added by both above
ways have their own copies across function instances
*********************************************************************/
functionDef.prototype.incrementVersion = function(){
this.version = this.version + 1;
}
var obj2 = new functionDef();
document.write(obj2.getVersion() + "<br />"); //v1
obj2.incrementVersion(); //incrementing version in obj2
//does not affect obj1 version
document.write(obj2.getVersion() + "<br />"); //v2
document.write(obj1.getVersion() + "<br />"); //v1
/*********************************************************************
4. `this` keyword refers to the immediate parent object. If you
nest the object through function prototype, then `this` inside
object refers to the nested object not the function instance
*********************************************************************/
functionDef.prototype.nestedObj = { name: 'nestedObj',
getName1 : function(){
return this+":"+this.name;
}
};
document.write(obj2.nestedObj.getName1() + "<br />"); //[object Object]:nestedObj
/*********************************************************************
5. If the method is on an object's prototype chain, `this` refers
to the object the method was called on, as if the method was on
the object.
*********************************************************************/
var ProtoObj = { fun: function () { return this.a } };
var obj3 = Object.create(ProtoObj); //creating an object setting ProtoObj
//as its prototype
obj3.a = 999; //adding instance member to obj3
document.write(obj3.fun()+"<br />");//999
//calling obj3.fun() makes
//ProtoObj.fun() to access obj3.a as
//if fun() is defined on obj3
4. When a function Object() { [native code] } function is utilised.
This inside function body points to the new object being produced when the function is used as a constructor (that is, when it is called with the new keyword).
var myname = "global context";
function SimpleFun()
{
this.myname = "simple function";
}
var obj1 = new SimpleFun(); //adds myname to obj1
//1. `new` causes `this` inside the SimpleFun() to point to the
// object being constructed thus adding any member
// created inside SimipleFun() using this.membername to the
// object being constructed
//2. And by default `new` makes function to return newly
// constructed object if no explicit return value is specified
document.write(obj1.myname); //simple function
5. When used within a prototype chain function.
This inside such method refers to the object the method was called on, as if the method was declared on the object, if the method is on an object’s prototype chain.
var ProtoObj = {
fun: function () {
return this.a;
}
};
//Object.create() creates object with ProtoObj as its
//prototype and assigns it to obj3, thus making fun()
//to be the method on its prototype chain
var obj3 = Object.create(ProtoObj);
obj3.a = 999;
document.write(obj3.fun()); //999
//Notice that fun() is defined on obj3's prototype but
//`this.a` inside fun() retrieves obj3.a
6. The call(), apply(), and bind() functions are all found within the call(), apply(), and bind() functions.
function add(inc1, inc2)
{
return this.a + inc1 + inc2;
}
var o = { a : 4 };
document.write(add.call(o, 5, 6)+"<br />"); //15
//above add.call(o,5,6) sets `this` inside
//add() to `o` and calls add() resulting:
// this.a + inc1 + inc2 =
// `o.a` i.e. 4 + 5 + 6 = 15
document.write(add.apply(o, [5, 6]) + "<br />"); //15
// `o.a` i.e. 4 + 5 + 6 = 15
var g = add.bind(o, 5, 6); //g: `o.a` i.e. 4 + 5 + 6
document.write(g()+"<br />"); //15
var h = add.bind(o, 5); //h: `o.a` i.e. 4 + 5 + ?
document.write(h(6) + "<br />"); //15
// 4 + 5 + 6 = 15
document.write(h() + "<br />"); //NaN
//no parameter is passed to h()
//thus inc2 inside add() is `undefined`
//4 + 5 + undefined = NaN</code>
7. event handlers within event handlers
I recommend trying this out with JSFiddle.
<script>
function clickedMe() {
alert(this + " : " + this.tagName + " : " + this.id);
}
document.getElementById("button1").addEventListener("click", clickedMe, false);
document.getElementById("button2").onclick = clickedMe;
document.getElementById("button5").attachEvent('onclick', clickedMe);
</script>
<h3>Using `this` "directly" inside event handler or event property</h3>
<button id="button1">click() "assigned" using addEventListner() </button><br />
<button id="button2">click() "assigned" using click() </button><br />
<button id="button3" onclick="alert(this+ ' : ' + this.tagName + ' : ' + this.id);">used `this` directly in click event property</button>
<h3>Using `this` "indirectly" inside event handler or event property</h3>
<button onclick="alert((function(){return this + ' : ' + this.tagName + ' : ' + this.id;})());">`this` used indirectly, inside function <br /> defined & called inside event property</button><br />
<button id="button4" onclick="clickedMe()">`this` used indirectly, inside function <br /> called inside event property</button> <br />
IE only: <button id="button5">click() "attached" using attachEvent() </button>
8. the arrow function in ES6
This will act similarly to common variables in an arrow function: it will be inherited from its lexical scope. The arrow function’s this will be the function’s this where the arrow function is specified.
As a result, this is the same behavior as:
(function(){}).bind(this)
Look at the code below:
const globalArrowFunction = () => {
return this;
};
console.log(globalArrowFunction()); //window
const contextObject = {
method1: () => {return this},
method2: function(){
return () => {return this};
}
};
console.log(contextObject.method1()); //window
const contextLessFunction = contextObject.method1;
console.log(contextLessFunction()); //window
console.log(contextObject.method2()()) //contextObject
const innerArrowFunction = contextObject.method2();
console.log(innerArrowFunction()); //contextObject
Answered by Mahesha999
Solution #3
Think about the following function:
function foo() {
console.log("bar");
console.log(this);
}
foo(); // calling the function
Note that we are running this in the normal mode, i.e. strict mode is not used.
When this is used in a browser, the value is logged as window. Because window is a global variable in the scope of a web browser, this is the case.
This would refer to the global variable in your app if you ran the same code in a node.js environment.
If we execute this in strict mode by adding “use strict”; at the beginning of the function definition, the global variable will no longer be referenced in either environment. This is done in rigorous mode to avoid any confusion. This would simply log undefined in this situation, because that is exactly what it is.
We’ll explore how to change the value of this in the following scenarios.
This can be accomplished in a variety of ways. If you’ve used Javascript to invoke native methods like forEach and slice, you already know that the this variable refers to the Object on which the function was called (Note that in javascript, just about everything is an Object, including Arrays and Functions). Take, for example, the following code.
var myObj = {key: "Obj"};
myObj.logThis = function () {
// I am a method
console.log(this);
}
myObj.logThis(); // myObj is logged
The attribute of an Object that holds a Function is called a method. When this method is called, this variable is always set to the Object it is associated with. Both stringent and non-strict modes are affected.
It’s worth noting that if a method is saved (or rather, copied) in another variable, the reference to it is lost in the new variable. Consider the following scenario:
// continuing with the previous code snippet
var myVar = myObj.logThis;
myVar();
// logs either of window/global/undefined based on mode of operation
Taking a look at a more common scenario:
var el = document.getElementById('idOfEl');
el.addEventListener('click', function() { console.log(this) });
// the function called by addEventListener contains this as the reference to the element
// so clicking on our element would log that element itself
Consider the following Javascript constructor function:
function Person (name) {
this.name = name;
this.sayHello = function () {
console.log ("Hello", this);
}
}
var awal = new Person("Awal");
awal.sayHello();
// In `awal.sayHello`, `this` contains the reference to the variable `awal`
What is the mechanism behind this? So, let’s have a look at what occurs when we apply the new keyword.
Pretty straightforward, eh?
It’s worth noting that the official ECMAScript specification makes no mention of such methods being constructor functions. They’re just regular functions, and new can be applied to any of them. It’s only that we refer to them as such since that’s how we use them.
So yeah, since functions are also Objects (and in-fact first class variables in Javascript), even functions have methods which are… well, functions themselves.
All functions inherit from the global Function, and call and apply are two of its many methods for manipulating the value of this in the function on which they are called.
function foo () { console.log (this, arguments); }
var thisArg = {myObj: "is cool"};
foo.call(thisArg, 1, 2, 3);
This is an example of how to use call. It basically takes the first parameter and stores it as a reference to thisArg in the function foo. All additional parameters supplied to call are passed as arguments to the function foo. As a result, the preceding code will log myObj: “is cool” in the console [1, 2, 3]. In any function, this is a rather nice approach to alter the value.
apply is similar to call with the exception that it only has two parameters: thisArg and an array of arguments to provide to the method. As a result, the preceding call can be interpreted as follows:
foo.apply(thisArg, [1,2,3])
Note that call and apply can override the value of this set by dot method invocation we discussed in the second bullet. It’s that simple:)
Call and apply’s brother is bind. It’s also a method that all Javascript functions inherit from the global Function constructor. The distinction between bind and call/apply is that call and apply both execute the function. bind, on the other hand, creates a new function with thisArg and arguments already defined. To further comprehend this, consider the following scenario:
function foo (a, b) {
console.log (this, arguments);
}
var thisArg = {myObj: "even more cool now"};
var bound = foo.bind(thisArg, 1, 2);
console.log (typeof bound); // logs `function`
console.log (bound);
/* logs `function () { native code }` */
bound(); // calling the function returned by `.bind`
// logs `{myObj: "even more cool now"}, [1, 2]`
Isn’t there a distinction between the three? It’s slight, but there’s a difference in how they’re utilized. By invoking the dot-method, bind, like call and apply, will override the value of this set.
It’s also worth noting that none of these three functions alter the original function. bind will return the newly formed function itself, ready to be called, whereas call and apply will return the value from newly constructed functions.
Sometimes, especially with nested scope, you don’t like how this changes with scope. Take a look at the sample below.
var myObj = {
hello: function () {
return "world"
},
myMethod: function () {
// copy this, variable names are case-sensitive
var that = this;
// callbacks ftw \o/
foo.bar("args", function () {
// I want to call `hello` here
this.hello(); // error
// but `this` references to `foo` damn!
// oh wait we have a backup \o/
that.hello(); // "world"
});
}
};
The value of this changed with the nested scope in the above code, but we wanted the value of this from the initial scope. As a result, we ‘copied’ this to that and used it instead of this. Isn’t that clever?
Index:
Answered by user3459110
Solution #4
It’s all about the extent of “this.” Every function has its own scope, and because everything in JS is an object, even a function can use “this” to hold values within itself. “This” is only relevant to instances of an object, according to OOP 101. As a result, each time a function is called, a new “instance” of that function is created, with a new “this” meaning.
Most users are perplexed when they try to utilize “this” inside anonymous closure functions such as:
(function(value) {
this.value = value;
$('.some-elements').each(function(elt){
elt.innerHTML = this.value; // uh oh!! possibly undefined
});
})(2);
So “this” doesn’t hold the “value” that you expect it to (from each()).
this.value = value;
(function(value) {
var self = this; // small change
self.value = value;
$('.some-elements').each(function(elt){
elt.innerHTML = self.value; // phew!! == 2
});
})(2);
Try it out; you’ll grow to appreciate this programming pattern.
Answered by arunjitsingh
Solution #5
Since this conversation has gained traction, I’ve produced a list of points for newcomers to the subject.
We use this in a similar fashion to how we use pronouns in natural languages like English: “John is sprinting to catch the train.” “… John is attempting to catch the train,” we may have written instead.
var person = {
firstName: "Penelope",
lastName: "Barrymore",
fullName: function () {
// We use "this" just as in the sentence above:
console.log(this.firstName + " " + this.lastName);
// We could have also written:
console.log(person.firstName + " " + person.lastName);
}
}
This doesn’t get a value until an object calls the function that defines it. All global variables and functions are defined on the window object under the global scope. As a result, this refers to (and has the value of) the global window object in a global function.
When using strict, the value of this in global and anonymous functions that aren’t connected to any object is undefined.
When: 1) we borrow a method that uses this, 2) we assign a method that uses this to a variable, 3) a function that uses this is supplied as a callback function, and 4) this is used inside a closure — an inner function, the this keyword is most misinterpreted. (2)
Arrow-functions, as defined in ECMA Script 6, take this binding from the enclosing (function or global) scope.
function foo() {
// return an arrow function
return (a) => {
// `this` here is lexically inherited from `foo()`
console.log(this.a);
};
}
var obj1 = { a: 2 };
var obj2 = { a: 3 };
var bar = foo.call(obj1);
bar.call( obj2 ); // 2, not 3!
While arrow-functions are a better alternative to bind(), it’s worth noting that they essentially disable the old approach in favor of more generally understood lexical scoping. (1)
References:
Answered by carlodurso
Post is based on https://stackoverflow.com/questions/3127429/how-does-the-this-keyword-work