call() a function within its own context

First Case:

In the first you are calling the function. And inside the function the function itself i.e f is set as this. So in first example this.x = 5; sets the property x on the function.

When the inner function is called this refers to window object so this.x = 3; changes the x property of window object.

When it logs console.log(this.x); here the same property x which was set as property of function is logged.

Second Case:

In the second example this inside the outer function refers to window so when this.x = 3; is evaluated the window.x becomes 3. As this refers to window in outer function so console.log(this.x); logs window.x which is 3

Conclusion:

The conclusion of the whole discussion is that if no argument is passed to call() then automatically window object is binded. According to MDN

thisArg

Optional. The value of this provided for the call to a function. Note that this may not be the actual value seen by the method: if the method is a function in non-strict mode, null and undefined will be replaced with the global object and primitive values will be converted to objects.

See the below snippet.

function foo(){
  console.log(this);
}
foo.call(foo); //foo function
foo.call(); //window object

If there is no specific context, this will be window. Your inner function always runs without a context, so it'll set window.x to 3. If you call f(), it will also run with this being window therefore logging the 3.

If you however do f.call(f), this will be the f function object, and it's x property will be set to 5.

  f.call(f)
  console.log(
    f.x, // 5
    window.x // 3
  );

I'd recommend stepping through it with the debugger if it isn't clear yet.