Function call forms and the value of this

Notes

There are 4 different ways that functions can be called, called “invocations”. We describe them briefly here, and we will go deeper into them later. A big difference is how this is treated in each case. Recall that this is a reserved word that typically represents the object under question. But in some function calls it is not as clear what that should mean.

A further complication is whether the function is defined as an arrow function or not.

Here is a little snippet of code that attempts to showcase these possibilities:

let o = {
  v: 2,
  f: function() { console.log(this); },
  g: () => console.log(this)
};

o.f();     // prints the object o
o.g();     // prints the global object
let f=o.f;
let g=o.g;
f();       // prints the global object
g();       // prints the global object
new f();   // a newly created object using f as its constructor.
new g();   // an error
f.call(o); // prints whatever argument is passed
g.call(o); // prints the global object

o.h = function() { this.l = () => console.log(this) };
o.h();     // Makes sure "l" is created while o is the current object
o.l();     // prints the object o

So the rules are basically as follows:

You need to be very careful when passing functions to some other part of your code, as you don’t necessarily know how they are going to be called.

Indirect Invocations

The indirect invocations deserve further notice. There are mainly 3 functions:

f.call

Calls f with the first argument serving as this and any subsequent arguments passed as arguments to f.

e.g. f.call(null, 1, 2, 3);

f.apply

Calls f with the first argument serving as this and the second argument being an array of the arguments to be used in the call.

e.g. f.apply(null, [1,2,3]);

f.bind

Does not actually call f, but it returns a function which behaves like f except that it has “bound” the this object, and optionally has bound some number of arguments.

e.g. f.bind(o, 1, 2)(3, 4) is the same as f.call(o, 1, 2, 3, 4).

bind was really important before we had arrow functions, because it allowed us to bind the this object and still pass the function to someone who needs to do something with it, while making sure we retain ownership of the object that the function will be acting on.