Value of "this" Flashcards

1
Q

What is this?

A

In non–strict mode, this is always a reference to an object. In strict mode, it can be any value.

The value of this depends on in which context it appears: function, class, or global.

“What is “this”?” (MDN Web Docs). Retrieved November 14, 2023.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
2
Q

What is the value of this on a function context?

A

Inside a function, the value of this depends on how the function is called. this is a binding that the language creates for you when the function body is evaluated.

For a typical function, the value of this is the object that the function is accessed on. In other words, if the function call is in the form obj.f(), then this refers to obj.

function getThis() {
  return this;
}

const obj1 = { name: "obj1" };
const obj2 = { name: "obj2" };

obj1.getThis = getThis;
obj2.getThis = getThis;

console.log(obj1.getThis()); // { name: 'obj1', getThis: [Function: getThis] }
console.log(obj2.getThis()); // { name: 'obj2', getThis: [Function: getThis] }

Please note that the value of this always changes based on how a function is called, even when the function was defined on an object at creation:

const obj4 = {
  name: "obj4",
  getThis() {
    return this;
  },
};

const obj5 = { name: "obj5" };

obj5.getThis = obj4.getThis;
console.log(obj5.getThis()); 
// { name: 'obj5', getThis: [Function: getThis] }

In strict mode:

  • If the value that the method is accessed on is a primitive, this will be a primitive value as well — but only if the function is in strict mode.
function getThisStrict() {
  "use strict"; // Enter strict mode
  return this;
}

// Only for demonstration — you should not mutate built-in prototypes
Number.prototype.getThisStrict = getThisStrict;
console.log(typeof (1).getThisStrict()); // "number"
  • If the function is called without being accessed on anything, this will be undefined — but only if the function is in strict mode.
console.log(typeof getThisStrict()); // "undefined"

In non strict mode, a special process called this substitution ensures that the value of this is always an object. This means:

  • If a function is called with this set to undefined or null, this gets substituted with globalThis.
  • If the function is called with this set to a primitive value, this gets substituted with the primitive value’s wrapper object.

“Function context” (MDN Web Docs). Retrieved November 14, 2023.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
3
Q

What is the value of this on arrow functions?

A

In arrow functions, this retains the value of the enclosing lexical context’s this. In other words, when evaluating an arrow function’s body, the language does not create a new this binding.

For example, in global code, this is always globalThis regardless of strictness, because of the global context binding:

const globalObject = this;
const foo = () => this;
console.log(foo() === globalObject); // true

Arrow functions create a closure over the this value of its surrounding scope, which means arrow functions behave as if they are “auto-bound” — no matter how it’s invoked, this is bound to what it was when the function was created (in the example above, the global object). The same applies to arrow functions created inside other functions: their this remains that of the enclosing lexical context.

Furthermore, when invoking arrow functions using call(), bind(), or apply(), the thisArg parameter is ignored. You can still pass other arguments using these methods, though.

const obj = { name: "obj" };
const foo = () => this;

// Attempt to set this using call
console.log(foo.call(obj) === globalObject); // true

// Attempt to set this using bind
const boundFoo = foo.bind(obj);
console.log(boundFoo() === globalObject); // true

“Function context” (MDN Web Docs). Retrieved November 14, 2023.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
4
Q

What is the benefit of using arrow functions on setTimeout()?

A

Arrow functions create closures over the this value of the enclosing execution context. So its this is permanently bound to the this of its enclosing function. With methods like setTimeout() and EventTarget.prototype.addEventListener() that usually require some kind of closure, instead of using call(), apply(), or bind() to ensure that the function is executed in the proper scope we can now use arrow functions.

Example:

const obj = {
  count: 10,
  doSomethingLater() {
    // The method syntax binds "this" to the "obj" context.
    setTimeout(() => {
      // Since the arrow function doesn't have its own binding and
      // setTimeout (as a function call) doesn't create a binding
      // itself, the "obj" context of the outer method is used.
      this.count++;
      console.log(this.count);
    }, 300);
  },
};

obj.doSomethingLater(); // logs 11
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
5
Q

What is the value of this in constructors?

A

When a function is used as a constructor (with the new keyword), its this is bound to the new object being constructed, no matter which object the constructor function is accessed on. The value of this becomes the value of the new expression unless the constructor returns another non–primitive value.

function C() {
  this.a = 37;
}

let o = new C();
console.log(o.a); // 37

function C2() {
  this.a = 37;
  return { a: 38 };
}

o = new C2();
console.log(o.a); // 38

“Function context” (MDN Web Docs). Retrieved November 14, 2023.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
6
Q

What is the value of this of a function invoked inside a super.method() call?

A

When a function is invoked in the super.method() form, the this inside the method function is the same value as the this value around the super.method() call, and is generally not equal to the object that super refers to. This is because super.method is not an object member access like the ones above — it’s a special syntax with different binding rules.

class Base {
  static getName() {
    console.log(this.name);
  }
}

class Extended extends Base {
  static getName() {
    super.getName();
  }
}

Extended.getName(); // Logs "Extended"

When calling super.prop as a function, the this value inside the prop function is the current this, not the object that super points to. For example, the super.getName() call logs "Extended", despite the code looking like it’s equivalent to Base.getName().

“Function context” (MDN Web Docs). Retrieved November 14, 2023.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
7
Q

Explain Class context

A

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.

“Class context” (MDN Web Docs). Retrieved November 28, 2023.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
8
Q

What is the value of this on the class static context?

A

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.

class C {
  instanceField = this;
  static staticField = this;
}

const c = new C();
console.log(c.instanceField === c); // true
console.log(C.staticField === C); // true

“Class context” (MDN Web Docs). Retrieved November 28, 2023.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
9
Q

What is the value of this on the class instance context?

A

Class constructors are always called with new, so their behavior is the same as function constructors: the this value is the new instance being created. Class methods behave like methods in object literals — the this value is the object that the method was accessed on. If the method is not transferred to another object, this is generally an instance of the class. Instance fields are evaluated with this set to the instance being constructed.

“Class context” (MDN Web Docs). Retrieved November 28, 2023.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
10
Q

What is the value of this on derived class constructors?

A

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:

this = new Base();

Warning: Referring to this before calling super() will throw an error.

Warning: Derived classes must not return before calling super(), unless the constructor returns an object (so the this value is overridden) or the class has no constructor at all.

“Class context” (MDN Web Docs). Retrieved November 28, 2023.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
11
Q

What is the value of this on the global context?

A

The this value depends on what execution context the script runs in. At the top level of a script, this refers to globalThis whether in strict mode or not. This is generally the same as the global object — for example, if the source is put inside an HTML <script> element and executed as a script, this === window.

const obj = { a: "Custom" };

// Variables declared with var become properties of 'globalThis'.
var a = "Global";

function whatsThis() {
  return this.a; // 'this' depends on how the function is called
}

whatsThis(); // 'Global'; the 'this' parameter defaults to 'globalThis' in non–strict mode
obj.whatsThis = whatsThis;
obj.whatsThis(); // 'Custom'; the 'this' parameter is bound to obj

If the source is loaded as a module (for HTML, this means adding type="module" to the <script> tag), this is always undefined at the top level.

If the source is executed with eval(), this is the same as the enclosing context for direct eval, or globalThis (as if it’s run in a separate global script) for indirect eval.

“Global context” (MDN Web Docs). Retrieved November 28, 2023.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
12
Q

How can you bind the value of this in a function?

A

With the bind() function method. For example, 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.

function f() {
  return this.a;
}

const g = f.bind({ a: "azerty" });
console.log(g()); // azerty

const h = g.bind({ a: "yoo" }); // bind only works once!
console.log(h()); // azerty

const o = { a: 37, f, g, h };
console.log(o.a, o.f(), o.g(), o.h()); // 37 37 azerty azerty

“The bind() method” (MDN Web Docs). Retrieved November 29, 2023.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
13
Q

bind() method

A

The bind() function creates a new bound function. Calling the bound function generally results in the execution of the function it wraps, which is also called the target function. The bound function will store the parameters passed — which include the value of this and the first few arguments — as its internal state.

Syntax

bind(thisArg)
bind(thisArg, arg1)
bind(thisArg, arg1, arg2)
bind(thisArg, arg1, arg2, /* …, */ argN)

Parameters

  • thisArg - The value to be passed as the this parameter to the target function func when the bound function is called. If the function is not in strict mode, null and undefined will be replaced with the global object, and primitive values will be converted to objects. The value is ignored if the bound function is constructed using the new operator.
  • arg1, …, argN Optional - Arguments to prepend to arguments provided to the bound function when invoking func.

Return value
A copy of the given function with the specified this value, and initial arguments (if provided).

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
14
Q

call() method

A

Normally, when calling a function, the value of this inside the function is the object that the function was accessed on. With call(), you can assign an arbitrary value as this when calling an existing function, without first attaching the function to the object as a property. This allows you to use methods of one object as generic utility functions.

Syntax

call(thisArg)
call(thisArg, arg1)
call(thisArg, arg1, arg2)
call(thisArg, arg1, arg2, /* …, */ argN)

Parameters

  • thisArg - The value to use as this when calling func. If the function is not in strict mode, null and undefined will be replaced with the global object, and primitive values will be converted to objects.
  • arg1, …, argN Optional - Arguments for the function.

Return value
The result of calling the function with the specified this value and arguments.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
15
Q

apply() method

A

Normally, when calling a function, the value of this inside the function is the object that the function was accessed on. With apply(), you can assign an arbitrary value as this when calling an existing function, without first attaching the function to the object as a property. This allows you to use methods of one object as generic utility functions.

Syntax

apply(thisArg)
apply(thisArg, argsArray)

Parameters

  • thisArg - The value of this provided for the call to func. If the function is not in strict mode, null and undefined will be replaced with the global object, and primitive values will be converted to objects.
  • argsArray Optional
    An array-like object, specifying the arguments with which func should be called, or null or undefined if no arguments should be provided to the function.

Return value
The result of calling the function with the specified this value and arguments.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
16
Q

How can you use apply() to find the maximum and minimum of an array of number elements?

A

Clever usage of apply() allows you to use built-in functions for some tasks that would probably otherwise require manually looping over a collection (or using the spread syntax).

For example, we can use Math.max() and Math.min() to find out the maximum and minimum value in an array.

// min/max number in an array
const numbers = [5, 6, 2, 3, 7];

// using Math.min/Math.max apply
let max = Math.max.apply(null, numbers);
// This about equal to Math.max(numbers[0], …)
// or Math.max(5, 6, …)

let min = Math.min.apply(null, numbers);

// vs. simple loop based algorithm
max = -Infinity;
min = +Infinity;

for (let i = 0; i < numbers.length; i++) {
  if (numbers[i] > max) {
    max = numbers[i];
  }
  if (numbers[i] < min) {
    min = numbers[i];
  }
}

Note this way of using apply is not really recommend. We should now favour the spread syntax. Added the flashcard because you may encounter its use if you deal with legacy code.