You're doing it backwards, don't try to positively match special characters, that limits what people can/must use. Instead, match something you consider to be not not special, e.g.:
pw.length >= 8 && /\d/.test(pw) && /[^a-z\d\x20]/i.test(pw)
Than checks length, presence of a digit, then presence of a character that's not alphanumeric nor a space (the i
flag makes it case-insensitive). You may also want to disallow spaces and other control characters that are not usually able to be typed on a keyboard (prevents people pasting in junk):
&& !/[\x00-\x20]/.test(pw)