I find myself challenged to think of a reason, because it's almost never necessary and is more expensive. It does, however, change the context, so it is useful to know that this tool is in the box.
Consider the flows and the context.
Alice => this.something() => f()
in f(), msg.sender is Alice and msg.value is whatever Alice sent.
Or
Alice => this.something() => this.f()
in f(), msg.sender is this and msg.value is whatever something() sent, which is probably 0.
The former is because f() would be running in the context of Alice's message. The latter is because a new message was initiated from this back to this. Consequently, it has its own context.
Hope it helps.
UPDATE
Thanks, Steve Marx, for some ideas about why this might be useful in some cases. You can carve off a portion of the ether or the gas and you can also carry on if f() fails, of you want to (not generally recommended). You would have to use call() to invoke this.f() to access such possibilities as .gas(), like this: What does Solidity's "call" function mean?. It will return (bool, bytes) where the bool is the success/failure of f() and the outer function (this) has a choice to continue or revert.
this.f()will automatically bubble up the revert). – user19510 Sep 22 '19 at 18:16