V8's string hashing implementation is in src/string-hasher-inl.h, its core part is the following function, which "adds" a new character to the "running hash", and is invoked in a loop for every character in the string:
uint32_t StringHasher::AddCharacterCore(uint32_t running_hash, uint16_t c) {
running_hash += c;
running_hash += (running_hash << 10);
running_hash ^= (running_hash >> 6);
return running_hash;
}
By definition, every hash table can have collisions. Whether collision attacks are a concern depends on the application (for example, a server processing client input might want to guard against collision-based DoS attacks; whereas a web browser typically doesn't need to care: if client-side script wanted to create useless CPU load, it could simply do for (;;) {}
-- but why would any script want to do that?).
A possible defense against collision attacks is to initialize ("salt") every string's "running hash" with a random value (that's e.g. chosen at application startup) instead of 0. That way attackers cannot predict which strings might have colliding hashes.