In most cases, the value of this is determined by how a function is called (runtime binding). It can't be set by assignment during execution, and it may be different each time the function is called. The Function.prototype.bind() method can set the value of a function's this regardless of how it's called, and arrow functions don't provide their own this binding (it retains the this value of the enclosing lexical context).
The value of this is not the object that has the function as an own property, but the object that is used to call the function. You can prove this by calling a method of an object up in the prototype chain.
In typical function calls, this is implicitly passed like a parameter through the function's prefix (the part before the dot). You can also explicitly set the value of this using the Function.prototype.call(), Function.prototype.apply(), or Reflect.apply() methods. Using Function.prototype.bind(), you can create a new function with a specific value of this that doesn't change regardless of how the function is called. When using these methods, the this substitution rules above still apply if the function is non-strict.
Occasionally, a callback is called with a this value other than undefined. For example, the reviver parameter of JSON.parse() and the replacer parameter of JSON.stringify() are both called with this set to the object that the property being parsed/serialized belongs to.
In the second example (C2), because an object was returned during construction, the new object that this was bound to gets discarded. (This essentially makes the statement this.a = 37; dead code. It's not exactly dead because it gets executed, but it can be eliminated with no outside effects.)
A class can be split into two contexts: static and instance. Constructors, methods, and instance field initializers (public or private) belong to the instance context. Static methods, static field initializers, and static initialization blocks belong to the static context. The this value is different in each context.
Static methods are not properties of this. They are properties of the class itself. Therefore, they are generally accessed on the class, and this is the value of the class (or a subclass). Static initialization blocks are also evaluated with this set to the current class.
Field initializers are also evaluated in the context of the class. Instance fields are evaluated with this set to the instance being constructed. Static fields are evaluated with this set to the current class. This is why arrow functions in field initializers are bound to the instance for instance fields and to the class for static fields.
Unlike base class constructors, derived constructors have no initial this binding. Calling super() creates a this binding within the constructor and essentially has the effect of evaluating the following line of code, where Base is the base class:
In the global execution context (outside of any functions or classes; may be inside blocks or arrow functions defined in the global scope), the this value depends on what execution context the script runs in. Like callbacks, the this value is determined by the runtime environment (the caller).
Note that some source code, while looking like the global scope, is actually wrapped in a function when executed. For example, Node.js CommonJS modules are wrapped in a function and executed with the this value set to module.exports. Event handler attributes are executed with this set to the element they are attached to.
Calling f.bind(someObject) creates a new function with the same body and scope as f, but the value of this is permanently bound to the first argument of bind, regardless of how the function is being called.
Arrow functions create closures over the this value of the enclosing execution context. In the following example, we create obj with a method getThisGetter that returns a function that returns the value of this. The returned function is created as an arrow function, so its this is permanently bound to the this of its enclosing function. The value of this inside getThisGetter can be set in the call, which in turn sets the return value of the returned function. We will assume that getThisGetter is a non-strict function, which means it's contained in a non-strict script and not further nested in a class or strict function.
We can call getThisGetter as a method of obj, which binds this to obj inside its body. The returned function is assigned to a variable fn. Now, when calling fn, the value of this returned is still the one set by the call to getThisGetter, which is obj. If the returned function was not an arrow function, such calls would cause the this value to be globalThis, because getThisGetter is non-strict.
But be careful if you unbind the method of obj without calling it, because getThisGetter is still a method that has a varying this value. Calling fn2()() in the following example returns globalThis, because it follows the this from fn2(), which is globalThis since it's called without being attached to any object.
This behavior is very useful when defining callbacks. Usually, each function expression creates its own this binding, which shadows the this value of the upper scope. Now, you can define functions as arrow functions if you don't care about the this value, and only create this bindings where you do (e.g. in class methods). See example with setTimeout().
this in getters and setters is based on which object the property is accessed on, not which object the property is defined on. A function used as getter or setter has its this bound to the object from which the property is being set or gotten.
When a function is used as an event handler, its this parameter is bound to the DOM element on which the listener is placed (some browsers do not follow this convention for listeners added dynamically with methods other than addEventListener()).
Just like with regular functions, the value of this within methods depends on how they are called. Sometimes it is useful to override this behavior so that this within classes always refers to the class instance. To achieve this, bind the class methods in the constructor:
Although with statements are deprecated and not available in strict mode, they still serve as an exception to the normal this binding rules. If a function is called within a with statement and that function is a property of the scope object, the this value is bound to the scope object, as if the obj1. prefix exists.
df19127ead