It just protects from precomputation of the hash values of the passwords. If there were no salts then the hash value of a given password would look the same in every database (if the same hash function was used). So if you would precompute a rainbow table, where you store the password next to the hash value of the password, you could attack every database easily in the same way by just comparing the hash values and using the password stored next to it in the rainbow table.
Now, with salting we get a unique hash value even if the password stays the same, rendering precomputation useless. The salt, however, is stored in plaintext next to the hash value: (hash, salt).
This does obviously not keep an attacker from computing the hash value = hash(password + salt) - it just helps against rainbow tables.
If you would still want to precompute a rainbow table the amount of memory needed would make it impractical. With n bit salts you would have to store 2^n entries for each password.