Aliases are also ugly in my opinion, given that they can be reassigned any old time. Even the much-used dollar sign alias demands extra scrutiny, when inspectng unfamiliar code. The advantage is that they're (aliases, that is) are easy to write, not easy read. On the other hand, the "contains" function should adhere to the sanest contract most would expect from it, and if it does, "contains" is easy enough to understand. But yeah, depending on libraries is either laziness or bullshit, when it comes to core language functionality. The only thing advanced libraries really offer is cross-browser compatibility.
Meanwhile, (x.indexOf(y) == -1) is dead simple, as long as you know that arrays start at zero, never have negative indices, and that indexOf() returns a negative value when the argument isn't matched by an object in the array. Returning a negative value, as parlance for "not found", when an absolute integer value is expected, is a pretty sane convention.
Those extra seconds add up and in my opinion readability is more about optimizing reading speed by using common shapes and patterns conventionally, not making something dumb proof.
It even suggests using a dependency like underscore for something that is already in the language. So if I don't use underscore, I need to stop my reading completely because my mind doesn't recognize this _(array).contains('foo') pattern and I need to actively read the entire line and in cases lookup the documentation of some random method in a random obscure _ library that I also need to lookup in the code to find the actual dependency name. Because even if I were to check the implementation of that underscore method using the IDE, it's even more obscure and magic. Good luck following the advice in this book.