ChatGPT解决这个技术问题 Extra ChatGPT

How does the "this" keyword work, and when should it be used?

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 this work and when should it be used?

I found this when I googled "this" quirksmode.org/js/this.html
Peter Michaux advocates against the use of this peter.michaux.ca/articles/javascript-widgets-without-this
An interesting explanation of this keyword: rainsoft.io/gentle-explanation-of-this-in-javascript

3
35 revs, 9 users 70%

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 specification

The 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.

1. Global execution context in scripts

This is script code evaluated at the top level, e.g. directly inside a <script>:

<script>
// Global context
console.log(this); // Logs global object.

setTimeout(function(){
  console.log("Not global context");
});
</script>

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.

2. Global execution context in modules

Modules have been introduced in ECMAScript 2015.

This applies to modules, e.g. when directly inside a <script type="module">, as opposed to a simple <script>.

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.

3. 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.

4. Entering function code

Entering function code occurs when calling a function.

There are four categories of syntax to invoke a function.

The EvaluateCall AO is performed for these three:3 Normal function calls Optional chaining calls Tagged templates

Normal function calls

Optional chaining calls

Tagged templates

And EvaluateNew is performed for this one:3 Constructor invocations

Constructor invocations

The actual function call happens at the Call AO, which is called with a thisValue determined from context; this argument is passed along in a long chain of call-related calls. Call calls the [[Call]] internal slot of the function. This calls PrepareForOrdinaryCall where a new function Environment Record is created:

A function Environment Record is a declarative Environment Record that is used to represent the top-level scope of a function and, if the function is not an ArrowFunction, provides a this binding. If a function is not an ArrowFunction function and references super, its function Environment Record also contains the state that is used to perform super method invocations from within the function.

In addition, there is the [[ThisValue]] field in a function Environment Record:

This is the this value used for this invocation of the function.

The NewFunctionEnvironment call also sets the function environment’s [[ThisBindingStatus]] property.

[[Call]] also calls OrdinaryCallBindThis, where the appropriate thisArgument is determined based on:

the original reference,

the kind of the function, and

whether or not the code is in strict mode.

Once determined, a final call to the BindThisValue method of the newly created function Environment Record actually sets the [[ThisValue]] field to the thisArgument.

Finally, this very field is where a function Environment Record’s GetThisBinding AO gets the value for this from:

The GetThisBinding concrete method of a function Environment Record envRec […] [does this]: […] 3. Return envRec.[[ThisValue]].

Again, how exactly the this value is determined depends on many factors; this was just a general overview. With this technical background, let’s examine all the concrete examples.

Arrow functions

When an arrow function is evaluated, the [[ThisMode]] internal slot of the function object is set to “lexical” in OrdinaryFunctionCreate.

At OrdinaryCallBindThis, which takes a function F:

Let thisMode be F.[[ThisMode]]. If thisMode is lexical, return NormalCompletion(undefined). […]

which just means that the rest of the algorithm which binds this is skipped. An arrow function does not bind its own this value.

So, what is this inside an arrow function, then? Looking back at ResolveThisBinding and GetThisEnvironment, the HasThisBinding method explicitly returns false.

The HasThisBinding concrete method of a function Environment Record envRec […] [does this]: If envRec.[[ThisBindingStatus]] is lexical, return false; otherwise, return true.

So the outer environment is looked up instead, iteratively. The process will end in one of the three environments that have a this binding.

This just means that, in arrow function bodies, this comes from the lexical scope of the arrow function, or in other words (from Arrow function vs function declaration / expressions: Are they equivalent / exchangeable?):

Arrow functions don’t have their own this […] binding. Instead, [this identifier is] resolved in the lexical scope like any other variable. That means that inside an arrow function, this [refers] to the [value of this] in the environment the arrow function is defined in (i.e. “outside” the arrow function).

Function properties

In normal functions (function, methods), this is determined by how the function is called.

This is where these “syntax variants” come in handy.

Consider this object containing a function:

const refObj = {
    func: function(){
      console.log(this);
    }
  };

Alternatively:

const refObj = {
    func(){
      console.log(this);
    }
  };

In any of the following function calls, the this value inside func will be refObj.1

refObj.func()

refObj["func"]()

refObj?.func()

refObj.func?.()

refObj.func``

If the called function is syntactically a property of a base object, then this base will be the “reference” of the call, which, in usual cases, will be the value of this. This is explained by the evaluation steps linked above; for example, in refObj.func() (or refObj["func"]()), the CallMemberExpression is the entire expression refObj.func(), which consists of the MemberExpression refObj.func and the Arguments ().

But also, refObj.func and refObj play three roles, each:

they’re both expressions,

they’re both references, and

they’re both values.

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 work very similarly: basically, 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 trying to get the [[Base]] property of the reference (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: Getters / Setters work the same way as methods, regarding this. Simple properties don’t affect the execution context, e.g. here, this is in global scope:

const o = {
    a: 1,
    b: this.a, // Is `globalThis.a`.
    [this.a]: 2 // Refers to `globalThis.a`.
  };

Calls without base reference, strict mode, and with

A call without a base reference is usually a function that isn’t called as a property. For example:

func(); // As opposed to `refObj.func();`.

This also happens when passing or assigning methods, or using the comma operator. This is where the difference between Reference Record and Value is relevant.

Note function j: following the specification, you will notice that j can only return the function object (Value) itself, but not a Reference Record. Therefore the base reference refObj is lost.

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.

EvaluateCall calls Call with a thisValue of undefined here. This makes a difference in OrdinaryCallBindThis (F: the function object; thisArgument: the thisValue passed to Call):

Let thisMode be F.[[ThisMode]]. […] If thisMode is strict, let thisValue be thisArgument. Else, If thisArgument is undefined or null, then Let globalEnv be calleeRealm.[[GlobalEnv]]. […] Let thisValue be globalEnv.[[GlobalThisValue]]. Else, Let thisValue be ! ToObject(thisArgument). NOTE: ToObject produces wrapper objects […]. […]

Note: step 5 sets the actual value of this to the supplied thisArgument in strict mode — undefined in this case. In “sloppy mode”, an undefined or null thisArgument results in this being the global this value.

If IsPropertyReference returns false, then EvaluateCall takes these steps:

Let refEnv be ref.[[Base]]. Assert: refEnv is an Environment Record. Let thisValue be refEnv.WithBaseObject().

This is where an undefined thisValue may come from: refEnv.WithBaseObject() is always undefined, except in with statements. In this case, thisValue will be the binding object.

There’s also Symbol.unscopables (Docs on MDN) to control the with binding behavior.

To summarize, so 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.

Note that when evaluating this, it doesn’t matter where a normal function is defined.

.call, .apply, .bind, thisArg, and primitives

Another consequence of step 5 of OrdinaryCallBindThis, in conjunction with step 6.2 (6.b in the spec), is that a primitive this value is coerced to an object only in “sloppy” mode.

To examine this, let’s introduce another source for the this value: the three methods that override the this binding:4

Function.prototype.apply(thisArg, argArray)

Function.prototype. {call, bind} (thisArg, ...args)

.bind creates a bound function, whose this binding is set to thisArg and cannot change again. .call and .apply call the function immediately, with the this binding set to thisArg.

.call and .apply map directly to Call, using the specified thisArg. .bind creates a bound function with BoundFunctionCreate. These have their own [[Call]] method which looks up the function object’s [[BoundThis]] internal slot.

Examples of setting a custom this value:

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 supply a primitive value:

function f(){
  console.log(this);
}

const myString = "s",
  g = f.bind(myString);

g();              // Logs `String { "s" }`.
f.call(myString); // Logs `String { "s" }`.

In non-strict mode, primitives are coerced to their object-wrapped form. It’s the same kind of object you get when calling Object("s") or new String("s"). In strict mode, you can use primitives:

"use strict";

function f(){
  console.log(this);
}

const myString = "s",
  g = f.bind(myString);

g();              // Logs `"s"`.
f.call(myString); // Logs `"s"`.

Libraries make use of these methods, e.g. jQuery sets the this to the DOM element selected here:

$("button").click(function(){
  console.log(this); // Logs the clicked button.
});

Constructors, classes, and new

When calling a function as a constructor using the new operator, EvaluateNew calls Construct, which calls the [[Construct]] method. If the function is a base constructor (i.e. not a class extends{}), it sets thisArgument to a new object created from the constructor’s prototype. Properties set on this in the constructor will end up on the resulting instance object. this is implicitly returned, unless you explicitly return your own non-primitive value.

A class is a new way of creating constructor functions, introduced in ECMAScript 2015.

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 definitions are implicitly in strict mode:

class A{
  m1(){
    return this;
  }
  m2(){
    const m1 = this.m1;
    
    console.log(m1());
  }
}

new A().m2(); // Logs `undefined`.

super

The exception to the behavior with new is class extends{}, as mentioned above. Derived classes do not immediately set their this value upon invocation; they only do so once the base class is reached through a series of super calls (happens implicitly without an own constructor). Using this before calling super is not allowed.

Calling super calls the super constructor with the this value of the lexical scope (the function Environment Record) of the call. GetThisValue has a special rule for super calls. It uses BindThisValue to set 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 }`.

5. Evaluating class fields

Instance fields and static fields were introduced in ECMAScript 2022.

When a class is evaluated, ClassDefinitionEvaluation is performed, modifying the running execution context. For each ClassElement:

if a field is static, then this refers to the class itself,

if a field is not static, then this refers to the instance.

Private fields (e.g. #x) and methods are added to a PrivateEnvironment.

Static blocks are currently a TC39 stage 3 proposal. Static blocks work the same as static fields and methods: this inside them refers to the class itself.

Note that in methods and getters / setters, this works just like in normal 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 equivalent to o.f(); (f)() is equivalent to f(). This is explained in this 2ality article (archived). Particularly see how a ParenthesizedExpression is evaluated.

2: It must be a MemberExpression, must not be a property, must have a [[ReferencedName]] of exactly "eval", and must be the %eval% intrinsic object.

3: Whenever the specification says “Let ref be the result of evaluating X.”, then X is some expression that you need to find the evaluation steps for. For example, evaluating a MemberExpression or CallExpression is the result of one of these algorithms. Some of them result in a Reference Record.

4: There are also several other native and host methods that allow providing a this value, notably Array.prototype.map, Array.prototype.forEach, etc. that accept a thisArg as their second argument. Anyone can make their own methods to alter this like (func, thisArg) => func.bind(thisArg), (func, thisArg) => func.call(thisArg), etc. As always, MDN offers great documentation.

Just for fun, test your understanding with some examples

For each code snippet, answer the question: “What is the value of this at the marked line? Why?”.

To reveal the answers, click the gray boxes.

if(true){ console.log(this); // What is `this` here? } globalThis. The marked line is evaluated in the initial global execution context. const obj = {}; function myFun(){ return { // What is `this` here? "is obj": this === obj, "is globalThis": this === globalThis }; } obj.method = myFun; console.log(obj.method()); obj. When calling a function as a property of an object, it is called with the this binding set to the base of the reference obj.method, i.e. obj. const obj = { myMethod: function(){ return { // What is `this` here? "is obj": this === obj, "is globalThis": this === globalThis }; } }, myFun = obj.myMethod; console.log(myFun()); globalThis. Since the function value myFun / obj.myMethod is not called off of an object, as a property, the this binding will be globalThis. This is different from Python, in which accessing a method (obj.myMethod) creates a bound method object. const obj = { myFun: () => ({ // What is `this` here? "is obj": this === obj, "is globalThis": this === globalThis }) }; console.log(obj.myFun()); globalThis. Arrow functions don’t create their own this binding. The lexical scope is the same as the initial global scope, so this is globalThis. function myFun(){ console.log(this); // What is `this` here? } const obj = { myMethod: function(){ eval("myFun()"); } }; obj.myMethod(); globalThis. When evaluating the direct eval call, this is obj. However, in the eval code, myFun is not called off of an object, so the this binding is set to the global object. function myFun() { // What is `this` here? return { "is obj": this === obj, "is globalThis": this === globalThis }; } const obj = {}; console.log(myFun.call(obj)); obj. The line myFun.call(obj); is invoking the special built-in function Function.prototype.call, which accepts thisArg as the first argument. class MyCls{ arrow = () => ({ // What is `this` here? "is MyCls": this === MyCls, "is globalThis": this === globalThis, "is instance": this instanceof MyCls }); } console.log(new MyCls().arrow()); It’s the instance of MyCls. Arrow functions don’t change the this binding, so it comes from lexical scope. Therefore, this is exactly the same as with the class fields mentioned above, like a = this;. Try changing it to static arrow. Do you get the result you expect?


Another common case: EventHandlers are invoked with this set to the currentTarget of the Event. These three proposals can be included in the future: Bind operator ::, Explicit this, this argument reflection. DOM 0 event attributes like onclick are also noteworthy: the JS code is implicitly wrapped in one with scope for document and one for the clicked element, causing confusion; this is the element that has the attribute.
@LRDPRDX Well, this answer is packed with every detail of this. But nobody really needs this in global scope, with is deprecated, eval is discouraged, strict mode should be used everywhere, etc. All that remains is that obj.method() calls method with obj as this if method is a function or a method; func() calls func without any this; .bind, .call, and .apply can be used to bind this explicitly; arrow functions don’t get a this binding. Classes: in static things, this refers to the class itself, in non-static things to the instance being created. That’s it.
You know, this is a great answer, but it really could use to be edited. Its very sloppy in some parts. And the the snippets at the end seem unnecessary for a site that is suppose to provide "encyclopedic-styled answers"
H
Haider Ilahi

The this keyword behaves differently in JavaScript compared to other languages. In Object Oriented languages, the this keyword refers to the current instance of the class. In JavaScript the value of this is determined by the invocation context of function (context.function()) and where it is called.

1. When used in global context

When you use this in global context, it is bound to global object (window in browser)

document.write(this);  //[object Window]

When you use this inside a function defined in the global context, this is still bound to global object since the function is actually made a method of global context.

function f1()
{
   return this;
}
document.write(f1());  //[object Window]

Above f1 is made a method of global object. Thus we can also call it on window object as follows:

function f()
{
    return this;
}

document.write(window.f()); //[object Window]

2. When used inside object method

When you use this keyword inside an object method, this is bound to the "immediate" enclosing object.

var obj = {
    name: "obj",
    f: function () {
        return this + ":" + this.name;
    }
};
document.write(obj.f());  //[object Object]:obj

Above I have put the word immediate in double quotes. It is to make the point that if you nest the object inside another object, then this is bound to the immediate parent.

var obj = {
    name: "obj1",
    nestedobj: {
        name:"nestedobj",
        f: function () {
            return this + ":" + this.name;
        }
    }            
}

document.write(obj.nestedobj.f()); //[object Object]:nestedobj

Even if you add function explicitly to the object as a method, it still follows above rules, that is this still points 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 invoking context-less function

When you use this inside function that is invoked without any context (i.e. not on any object), it is bound to the global object (window in browser)(even if the function is defined inside the 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 it all with functions

We can try above points with functions too. However there are some differences.

Above we added members to objects using object literal notation. We can add members to functions by using this. to specify them.

Object literal notation creates an instance of object which we can use immediately. With function we may need to first create its instance using new operator.

Also in an object literal approach, we can explicitly add members to already defined object using dot operator. This gets added to the specific instance only. However I have added variable to the function prototype so that it gets reflected in all instances of the function.

Below I tried out all the things that we did with Object and this above, but by first creating function instead of directly writing an object.

/********************************************************************* 
  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 used inside constructor function.

When the function is used as a constructor (that is when it is called with new keyword), this inside function body points to the new object being constructed.

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 inside function defined on prototype chain

If the method is on an object's prototype chain, this inside such method refers to the object the method was called on, as if the method is defined on the object.

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. Inside call(), apply() and bind() functions

All these methods are defined on Function.prototype.

These methods allows to write a function once and invoke it in different context. In other words, they allows to specify the value of this which will be used while the function is being executed. They also take any parameters to be passed to the original function when it is invoked.

fun.apply(obj1 [, argsArray]) Sets obj1 as the value of this inside fun() and calls fun() passing elements of argsArray as its arguments.

fun.call(obj1 [, arg1 [, arg2 [,arg3 [, ...]]]]) - Sets obj1 as the value of this inside fun() and calls fun() passing arg1, arg2, arg3, ... as its arguments.

fun.bind(obj1 [, arg1 [, arg2 [,arg3 [, ...]]]]) - Returns the reference to the function fun with this inside fun bound to obj1 and parameters of fun bound to the parameters specified arg1, arg2, arg3,....

By now the difference between apply, call and bind must have become apparent. apply allows to specify the arguments to function as array-like object i.e. an object with a numeric length property and corresponding non-negative integer properties. Whereas call allows to specify the arguments to the function directly. Both apply and call immediately invokes the function in the specified context and with the specified arguments. On the other hand, bind simply returns the function bound to the specified this value and the arguments. We can capture the reference to this returned function by assigning it to a variable and later we can call it any time.

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. this inside event handlers

When you assign function directly to event handlers of an element, use of this directly inside event handling function refers to the corresponding element. Such direct function assignment can be done using addeventListener method or through the traditional event registration methods like onclick.

Similarly, when you use this directly inside the event property (like

W
WeiChing 林煒清

Javascript's this

Simple function invocation

Consider 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 running in a browser, the value of this would be logged as window. This is because window is the global variable in a web browser's scope.

If you run this same piece of code in an environment like node.js, this would refer to the global variable in your app.

Now if we run this in strict mode by adding the statement "use strict"; to the beginning of the function declaration, this would no longer refer to the global variable in either of the environments. This is done to avoid confusions in strict mode. this would, in this case just log undefined, because that is what it is, it is not defined.

In the following cases, we would see how to manipulate the value of this.

Calling a function on an object

There are different ways to do this. If you have called native methods in Javascript like forEach and slice, you should already know that the this variable in that case refers to the Object on which you called that function (Note that in javascript, just about everything is an Object, including Arrays and Functions). Take the following code for example.

var myObj = {key: "Obj"};
myObj.logThis = function () {
    // I am a method
    console.log(this);
}
myObj.logThis(); // myObj is logged

If an Object contains a property which holds a Function, the property is called a method. This method, when called, will always have it's this variable set to the Object it is associated with. This is true for both strict and non-strict modes.

Note that if a method is stored (or rather, copied) in another variable, the reference to this is no longer preserved in the new variable. For example:

// continuing with the previous code snippet

var myVar = myObj.logThis;
myVar();
// logs either of window/global/undefined based on mode of operation

Considering a more commonly practical 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

The new keyword

Consider a constructor function in Javascript:

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`

How does this work? Well, let's see what happens when we use the new keyword.

Calling the function with the new keyword would immediately initialize an Object of type Person. The constructor of this Object has its constructor set to Person. Also, note that typeof awal would return Object only. This new Object would be assigned the prototype of Person.prototype. This means that any method or property in the Person prototype would be available to all instances of Person, including awal. The function Person itself is now invoked; this being a reference to the newly constructed object awal.

Pretty straightforward, eh?

Note that the official ECMAScript spec nowhere states that such types of functions are actual constructor functions. They are just normal functions, and new can be used on any function. It's just that we use them as such, and so we call them as such only.

Calling functions on Functions: call and apply

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 two of its many methods are call and apply, and both can be used to manipulate 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 a typical example of using call. It basically takes the first parameter and sets this in the function foo as a reference to thisArg. All other parameters passed to call is passed to the function foo as arguments.
So the above code will log {myObj: "is cool"}, [1, 2, 3] in the console. Pretty nice way to change the value of this in any function.

apply is almost the same as call accept that it takes only two parameters: thisArg and an array which contains the arguments to be passed to the function. So the above call call can be translated to apply like this:

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. Simple enough :)

Presenting.... bind!

bind is a brother of call and apply. It is also a method inherited by all functions from the global Function constructor in Javascript. The difference between bind and call/apply is that both call and apply will actually invoke the function. bind, on the other hand, returns a new function with the thisArg and arguments pre-set. Let's take an example to better understand this:

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]`

See the difference between the three? It is subtle, but they are used differently. Like call and apply, bind will also over-ride the value of this set by dot-method invocation.

Also note that neither of these three functions do any change to the original function. call and apply would return the value from freshly constructed functions while bind will return the freshly constructed function itself, ready to be called.

Extra stuff, copy this

Sometimes, you don't like the fact that this changes with scope, especially nested scope. Take a look at the following example.

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"
        });
    }
  };

In the above code, we see that the value of this changed with the nested scope, but we wanted the value of this from the original scope. So we 'copied' this to that and used the copy instead of this. Clever, eh?

Index:

What is held in this by default? What if we call the function as a method with Object-dot notation? What if we use the new keyword? How do we manipulate this with call and apply? Using bind. Copying this to solve nested-scope issues.


D
Daniel Alexiuc

"this" is all about scope. Every function has its own scope, and since everything in JS is an object, even a function can store some values into itself using "this". OOP 101 teaches that "this" is only applicable to instances of an object. Therefore, every-time a function executes, a new "instance" of that function has a new meaning of "this".

Most people get confused when they try to use "this" inside of anonymous closure functions like:

(function(value) {
    this.value = value;
    $('.some-elements').each(function(elt){
        elt.innerHTML = this.value;        // uh oh!! possibly undefined
    });
})(2);

So here, inside each(), "this" doesn't hold the "value" that you expect it to (from

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 begin to like this pattern of programming


"everything in JS is an object" is not true, JavaScript also has primitive values, see bclary.com/2004/11/07/#a-4.3.2
The primitive values seem to have some methods on themselves, like String#substring(), Number#toString(), etc.. So, maybe not with the same nomenclature as that article, they really behave as if they were objects (they are all prototyped, ie. String#substring() is really: String.prototype.substring = function(){...}). Please correct me if I'm wrong.
The this keyword has nothing to do with scope. Also, it has a meaning also in functions that are not properties of objects.
@arunjitsingh—there are two schools of thought on that. I like the one that says "everything is an object, but some can be represented by primitives for convenience". ;-)
this is not ALL about scope. It is ALL about execution context, which is not the same thing as scope. JavaScript is lexically scoped (meaning scope is determined by the location of the code), but this is determined by how the function containing it is invoked - not where that function is.
c
carlodurso

Since this thread has bumped up, I have compiled few points for readers new to this topic.

How is the value of this determined?

We use this similar to the way we use pronouns in natural languages like English: “John is running fast because he is trying to catch the train.” Instead we could have written “… John is trying to catch the train”.

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 is not assigned a value until an object invokes the function where it is defined. In the global scope, all global variables and functions are defined on the window object. Therefore, this in a global function refers to (and has the value of) the global window object.

When use strict, this in global and in anonymous functions that are not bound to any object holds a value of undefined.

The this keyword is most misunderstood 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 passed as a callback function, and 4) this is used inside a closure — an inner function. (2)

https://i.stack.imgur.com/nPSkX.png

What holds the future

Defined in ECMA Script 6, arrow-functions adopt the 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 provide an alternative to using bind(), it’s important to note that they essentially are disabling the traditional this mechanism in favor of more widely understood lexical scoping. (1)

References:

this & Object Prototypes, by Kyle Simpson. © 2014 Getify Solutions. javascriptissexy.com - http://goo.gl/pvl0GX Angus Croll - http://goo.gl/Z2RacU


P
Pang

this in JavaScript always refers to the 'owner' of the function that is being executed.

If no explicit owner is defined, then the top most owner, the window object, is referenced.

So if I did

function someKindOfFunction() {
   this.style = 'foo';
}

element.onclick = someKindOfFunction;

this would refer to the element object. But be careful, a lot of people make this mistake.

<element onclick="someKindOfFunction()">

In the latter case, you merely reference the function, not hand it over to the element. Therefore, this will refer to the window object.


B
Ben Aston

Every execution context in javascript has a this parameter that is set by:

How the function is called (including as an object method, use of call and apply, use of new) Use of bind Lexically for arrow functions (they adopt the this of their outer execution context) Whether the code is in strict or non-strict mode Whether the code was invoked using eval

You can set the value of this using func.call, func.apply or func.bind.

By default, and what confuses most beginners, when a listener is called after an event is raised on a DOM element, the this value of the function is the DOM element.

jQuery makes this trivial to change with jQuery.proxy.


It's a little more correct to say that every function call has a scope. In other words, what's confusing about this in Javascript is that it's not an intrinsic property of the function itself, but rather an artifact of the way the function is invoked.
@pointy thanks. what causes the most confusion about this in js is the fact that in all the languages used earlier (c#, c++), - this can't be manipulated n always points to the object instance whereas in js it depends and can be changed when invoking functions using func.call, func.bind etc. – Sushil
this does not reference a function's scope. this will reference a specific object (or possibly undefined), which as you've said can be changed using .call() or .apply(). A function's scope is (essentially, when simplified) which variables it has access to, and this depends entirely on where the function is declared and cannot be changed.
@Pointy: "It's a little more correct to say that every function call has a scope." Even more correct to say that functions (and now blocks) have scope, function calls have context. Scope defines what the identifiers are that can be used by code in that scope. Context defines what those identifiers are bound to.
"Whatever that scope is, is referenced by "this"." No, this and scope have nothing whatsoever to do with one another in ES5 and before (e.g., when this answer was written). In ES2015 (aka ES6), this and scope are related one fairly minimal way wrt arrow functions (the this in an arrow function is inherited from its enclosing scope), but this never refers to a scope.
A
Arman

Daniel, awesome explanation! A couple of words on this and good list of this execution context pointer in case of event handlers.

In two words, this in JavaScript points the object from whom (or from whose execution context) the current function was run and it's always read-only, you can't set it anyway (such an attempt will end up with 'Invalid left-hand side in assignment' message.

For event handlers: inline event handlers, such as <element onclick="foo">, override any other handlers attached earlier and before, so be careful and it's better to stay off of inline event delegation at all. And thanks to Zara Alaverdyan who inspired me to this list of examples through a dissenting debate :)

el.onclick = foo; // in the foo - obj

el.onclick = function () {this.style.color = '#fff';} // obj

el.onclick = function() {doSomething();} // In the doSomething - Window

el.addEventListener('click',foo,false) // in the foo - obj

el.attachEvent('onclick, function () { // this }') // window, all the compliance to IE :)

g
gnerkus

Here is one good source of this in JavaScript.

Here is the summary:

global this In a browser, at the global scope, this is the windowobject