Well, not the class instance itself, but variables used in the resulting query are escaped for you. Looking through the source code is not very comforting, there isn’t any $wpdb->prepare() just before the query is run, as one might expect. Individual elements are escaped in one place or another before getting to the final query string.
A recommendation is an opinion and as such, the answer will vary by coder and situation. IMO, it depends. In general, WP_Query is easier to use – it escapes variables, handles pagination, etc. But it is not entirely flexible. You cannot do any kind of query you want. Any query that is possible can be done through $wpdb methods. With $wpdb, it does require more care, like using prepare() when called for. More confusing is a few methods do not require it. However, it usually doesn’t hurt much to use prepare() needlessly.