Простой ответ:
Берём метод:
метод = function(){
console.log(this)
};
и(не важно как) пихаем его в какие-то объекты.
Получаем:
хрень.метод() // this - хрень
хрень.кишки.метод() // this - хрень.кишки
метод() // this - window
хрень.метод.call(хрень.кишки) // this - хрень.кишки
метод.call(хрень.кишки) // this - хрень.кишки
метод.call(null) // this - null
элемент.addEventListener('оппа', хрень.метод) // this -элемент
элемент.addEventListener('оппа', метод) // this -элемент
элемент.addEventListener('оппа', хрень.кишки.продукт.метод) // this -элемент
По сути this для фукции - это то, что идёт перед точкой, кроме тех случаев когда он переопределён явно. Всё, никакой эзотерики.)
fn.call(!this ? this : obj)
- это чушь скорее всего. Если this -
falsy, то ставим его как this при вызове функции fn, иначе ставим obj. Falsy this может быть только при явном указании(или в strict режиме, при вызове функции напрямую("без точки перед ней")), и скорее всего передача пустого this в таком случае просто сломает выполнение fn.
Ну ещё следует упомянуть стрелочную фукнцию:
метод = () => {
console.log(this)
};
это можно считать за явное указание this, потому что this тут всегда привязан тот, что был при создании стрелочной функции, независимо от того как и откуда её вызывают.