Firstly, 'a.substring()' returns the substring starting from the index given as parameter, so while using 'a.substring(1)' as the parameter of the recursive method the first character always gets skipped and the length of the string given as parameter decreases gradually. Once no character remains it reaches the base case.
Secondly, 'a.charAt()' returns the character exists at the index of the string given as parameter. So 'a.charAt(0)' returns the first index of the string 'a' which is given as the parameter of the recursive method.
Finally, the first code works because each time it sends the entire string except the first character and it includes that first character at the end of the string that is returned reversed. So at the end, the entire string gets reversed.
On the other hand, the second code includes the entire substring starting from the first index of the string given as its parameter instead of the first character.
To make the code work you can either use 'charAt(0)' like the first code -
return reverse(a.substring(1)) + a.charAt(0);
or you can use 'a.substring(0, 1)' which considers only the first character as the substring and returns it -
return reverse(a.substring(1)) + a.substring(0, 1);