Использование переменной self для this — это уже костыль?
Не всегда. Иногда, вам внутри контекста бывает нужно получить доступ к this (текущий контекст) и к внешнему контексту. В этом случае придется внешний сохранять в переменную.
Если же такой необходимости нет, то удобнее использовать стрелочные функции и отказаться от self.
Это плохая практика и не стоит так делать, вместо этого можно объявить стрелочную функцию которая возьмет контекст того уровня где объявлена или сделать .bind(this), но лучше все же стрелочной функцией, только надо учесть что если требуются старый браузеры то нужно собрать код под них используй babel + webpack/parcel и тд.