Neither ls nor grep need anything open on their fd 3 (they don't use that fd), so it's better practice to close it (release the resources you don't need). We only use that fd 3 to be able to restore ls stdout to the original one (before executing ls).
Remember that in a pipe line, all commands run concurrently in their own process. Redirections apply for each separately, so closing the fd 3 for one cannot close it for the other one.
It won't make much difference in practice in this case to close or not to close other than you might reach a limit on the number of file descriptors sooner if you don't.
In other cases (commands themselves starting other processes for instance), that may hold resources and cause problems. Think for instance if stdout is a pipe for instance, a background process may end up inheriting that fd, preventing any reader from that pipe to see EOF until that process has returned.
A better way to write it would be:
{ ls -l 2>&1 >&3 3>&- | grep bad 3>&-; } 3>&1
That way, the fd 3 is only redirected temporarily for the duration of that command group (and restored afterwards or closed).
See the difference:
$ { ls -l /proc/self/fd 2>&1 >&3 3>&- | grep bad 3>&-; } 3>&1 total 0 lrwx------ 1 stephane stephane 64 Apr 2 09:29 0 -> /dev/pts/4 lrwx------ 1 stephane stephane 64 Apr 2 09:29 1 -> /dev/pts/4 l-wx------ 1 stephane stephane 64 Apr 2 09:29 2 -> pipe:[575886] lr-x------ 1 stephane stephane 64 Apr 2 09:29 3 -> /proc/20918/fd/ $ { ls -l /proc/self/fd 2>&1 >&3 | grep bad 3>&-; } 3>&1 total 0 lrwx------ 1 stephane stephane 64 Apr 2 09:29 0 -> /dev/pts/4 lrwx------ 1 stephane stephane 64 Apr 2 09:29 1 -> /dev/pts/4 l-wx------ 1 stephane stephane 64 Apr 2 09:29 2 -> pipe:[575900] lrwx------ 1 stephane stephane 64 Apr 2 09:29 3 -> /dev/pts/4 lr-x------ 1 stephane stephane 64 Apr 2 09:29 4 -> /proc/20926/fd/
In the second invocation, ls had its fd 3 also open to the terminal (which was open on stdout at the time I ran the pipeline) for no good reason.
Note that in ksh93, with exec, you don't need to close those fds as fds other than 0, 1, 2 are automatically closed upon executing a command.
$ ksh93 -c 'exec 3>&1; ls -l /dev/fd/' total 0 lrwx------ 1 stephane stephane 64 Apr 2 09:34 0 -> /dev/pts/16 lrwx------ 1 stephane stephane 64 Apr 2 09:34 1 -> /dev/pts/16 lrwx------ 1 stephane stephane 64 Apr 2 09:34 2 -> /dev/pts/16 lr-x------ 1 stephane stephane 64 Apr 2 09:34 3 -> /proc/21105/fd $ ksh93 -c 'exec 3>&1; ls -l /dev/fd/ 3>&3' total 0 lrwx------ 1 stephane stephane 64 Apr 2 09:34 0 -> /dev/pts/16 lrwx------ 1 stephane stephane 64 Apr 2 09:34 1 -> /dev/pts/16 lrwx------ 1 stephane stephane 64 Apr 2 09:34 2 -> /dev/pts/16 lrwx------ 1 stephane stephane 64 Apr 2 09:34 3 -> /dev/pts/16 lr-x------ 1 stephane stephane 64 Apr 2 09:34 4 -> /proc/21108/fd
I don't know why it says (but not 'ls') above, sounds like a mistake (possibly mine ;-).