search

Home  >  Q&A  >  body text

Understand the function and appropriate usage of the "this" keyword

I would like to find a clear explanation of what the "this" keyword does and how to use it correctly.

It seems to be behaving strangely and I don't entirely understand why.

thisHow does it work and when should you use it?

P粉155551728P粉155551728459 days ago608

reply all(2)I'll reply

  • P粉087951442

    P粉0879514422023-10-13 14:03:41

    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 function's calling context (context.function()) and the location from which it was called.

    <强>1. When used in a global context

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

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

    When you use this inside a function defined in the global context, this is still bound to the global object because the function is actually a method of the global context. < /p>

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

    The above f1 is a method of a global object. So we can also call it on the window object like this:

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

    <强>2. When used inside an object method

    When you use the this keyword in an object method, this is bound to the "direct" 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 "immediately" in double quotes. This is to indicate that if an object is nested within another object, this is bound to the immediate 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 function as a method to an object, it still follows the above rules, i.e. this still points to the direct 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 calling a context-free function

    When you use this inside a function that is called without any context (i.e. not on any object), it is bound to the global object (window# in the 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

    Try everything with functions

    We can also use functions to try the above points. But there are still some differences.

      Above we added members to the object using object literal notation. We can add members to a function using
    • this. to specify them.
    • Object literal notation creates an object instance that we can use immediately. For functions, we may need to first create an instance of it using the
    • new operator.
    • Also in the object literal method, we can use the dot operator to explicitly add members to the defined object. This is only added to specific instances. However, I have added the variable to the function prototype so that it is reflected in all instances of the function.
    Below I tried everything I did above with Object and

    this but first created the function instead of writing the object directly.

    /********************************************************************* 
      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() + "
    "); //[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() + "
    "); //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() + "
    "); //v1 obj2.incrementVersion(); //incrementing version in obj2 //does not affect obj1 version document.write(obj2.getVersion() + "
    "); //v2 document.write(obj1.getVersion() + "
    "); //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() + "
    "); //[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()+"
    ");//999 //calling obj3.fun() makes //ProtoObj.fun() to access obj3.a as //if fun() is defined on obj3

    4. When used inside a constructor<强>.

    When a function is used as a constructor (that is, when called using the

    new keyword), this in the 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
    < /p>

    5. When used inside a function defined on the prototype chain<强>

    If the method is on the object's prototype chain,

    this within the method refers to the object on which the method is called, as if the method was defined on that 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. Internal call(), apply() and bind() functions<强>

    • All these methods are defined on Function.prototype.
    • These methods allow writing a function once and calling it in different contexts. In other words, they allow specifying the this value that will be used when executing the function. They can also pass any arguments to the original function when it is called.
    • fun.apply(obj1 [, argsArray]) Set obj1 to the value within this code>fun() and calls fun(), passing the elements of argsArray as its arguments.
    • fun.call(obj1 [, arg1 [, arg2 [,arg3 [, ...]]]]) - Set obj1 as fun () the value of this and calls fun() passing arg1, arg2, arg3, ...< /code> as its arguments.
    • fun.bind(obj1 [, arg1 [, arg2 [,arg3 [, ...]]]]) - Returns a reference to the functionfun, where this in fun is bound to obj1, and the parameters of fun are bound to the specified parameters arg1, arg2, arg3, ....
    • Now, the difference between apply, call and bind must be obvious. apply Allows arguments to be specified as array-like objects, that is, objects with a numeric length property and a corresponding non-negative integer property. And call allows the parameters of the function to be specified directly. Both apply and call immediately call the function in the specified context and with the specified parameters. bind, on the other hand, simply returns the function bound to the specified this value and arguments. We can capture a reference to this returned function by assigning it to a variable, which we can then call at any time.
    function add(inc1, inc2)
    {
        return this.a + inc1 + inc2;
    }
    
    var o = { a : 4 };
    document.write(add.call(o, 5, 6)+"
    "); //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]) + "
    "); //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()+"
    "); //15 var h = add.bind(o, 5); //h: `o.a` i.e. 4 + 5 + ? document.write(h(6) + "
    "); //15 // 4 + 5 + 6 = 15 document.write(h() + "
    "); //NaN //no parameter is passed to h() //thus inc2 inside add() is `undefined` //4 + 5 + undefined = NaN

    7. this

    within the event handler
    • When you assign a function directly to an element's event handler, use this directly within the event handler function to reference the corresponding element. This direct function assignment can be done using the addeventListener method or via traditional event registration methods such as onclick.
    • Similarly, when you use this
    • However, indirect use of this through other functions called within event handlers or event properties resolves to the global object window.
    • The same behavior as above can be achieved when we attach a function to an event handler using Microsoft's event registration model method attachEvent. Instead of assigning a function to an event handler (thus creating a function method of the element), it calls the function on the event (effectively calling it in the global context).

    I suggest to use JSFiddle.

    sssccc
    
    

    Using `this` "directly" inside event handler or event property



    Using `this` "indirectly" inside event handler or event property



    IE only:

    <强>8. this

    in ES6 arrow functions

    In an arrow function, this behaves like a public variable: it will be inherited from its lexical scope. The this of the function that defines the arrow function will be the this of the arrow function.

    So, this is the same behavior as:

    (function(){}).bind(this)

    Please refer to the following code:

    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 
    

    reply
    0
  • P粉156532706

    P粉1565327062023-10-13 11:53:32

    This is a keyword in JavaScript that is an attribute of the execution context. Its main use is in functions and constructors. The rules for this are pretty simple (if you stick to best practices).

    Technical description of this in the specification

    ECMAScript StandardDefinitionthis By abstract operation (abbreviated as AO) ResolveThisBinding:

    Global environment records, Module environment records, and Function environment recordseach have their own GetThisBinding method.

    GetThisEnvironment AO finds the LexicalEnvironment of the current running execution context and finds the closest ascending environment record (by iterating through its [[OuterEnv]] property) that has this< /em> Binding (i.e. HasThisBinding returns true). The process ends with one of three environment record types.

    The value of

    this usually depends on whether the code is in strict mode.

    The return value of

    GetThisBinding reflects the value of this for the current execution context, so this will resolve to a different value each time a new execution context is established. This can also happen when the current execution context is modified. The following subsections list five scenarios in which this might occur.

    You can place code samples into the AST Explorer to follow the specification details.

    1. Global execution context in scripts

    This is the script code evaluated at the top level, e.g. directly in

    When within the script's initial global execution context, evaluating this causes GetThisBinding to take the following steps:

    The global environment record's [[GlobalThisValue]] property is always set to a host-defined global object accessible via globalThis ( on the Web window, global on Node.js; Documentation on MDN). Follow the steps in InitializeHostDefinedRealm to learn how the [[GlobalThisValue]] property is generated.

    2. Global execution context in module

    Modules were introduced in ECMAScript 2015.

    This applies to modules e.g. directly inside