With the hashbang, the kernel runs the named interpreter passing it the script file name and the arguments you give, i.e. the command line is /bin/bash ./my_script.sh top, and that shows in the process listing with e.g. ps, and similarly pgrep finds it. It matches the keyword top, after all.
Without the hashbang, the kernel-level system call fails, and Bash runs the script itself, internally, and the arguments don't show in the process listing. (The shells do that, some way or another. IIRC it's a POSIX requirement that non-executable files be run through the shell if possible.)
It's easier to test with e.g. these two:
bash$ cat wait.sh
#!/bin/bash
sleep 50
bash$ cat wait2.sh
sleep 50
bash$ ./wait.sh & ./wait2.sh & ps uax |grep wait
ilkkachu 9029 0.0 0.0 15368 3060 pts/21 S 20:01 0:00 /bin/bash ./wait.sh
ilkkachu 9032 0.0 0.0 16964 968 pts/21 S+ 20:01 0:00 grep wait
the one without the hashbang doesn't show up.
I think pgrep is smart enough not to find itself, but to help it not find the script, you could use a pattern like '[t]op', which matches top, but not itself. With ./my_script.sh '[t]op', the difference disappears.
The command substitution there is useless, though, just drop it and run pgrep directly.