Jared Westover explains the difference:
After creating a SQL script and a pull request, a savvy developer left a comment on the PR because they were confused about why I was using both XACT_ABORT and TRY…CATCH. They thought that including both in one script was redundant. That got me thinking: is it true that setting XACT_ABORT ON makes TRY…CATCH redundant?
The most interesting part of this post is the cases in which you would use both in the same script.