A „bag of words“ usually describes encoding of text where one word (or ngram) is represented as one variable (column). This can be done as binary encoding or as count of words, often called one-hot encoding. Alternatively, you can introduce weights to represent the frequency of words in a document, such as TFIDF. See also here for a sklearn implementation. Hashing essentially is a „bag of words“ using the hashing trick to cope with previously unseen words in a corpus and a large (or growing) corpus.
In word2vec, each word is represented by a vector, which indicates how close one word is to another (this is the result of a pre-trained model). You can use a pre-trained word2vec model and assess the proximity of words by comparing two (word) vectors e.g. based on the Euclidean distance. These vectors help models to better understand the (semantic) structure of some text via understanding the empirical co-occurance of words (which is not possible with one-hot encoding etc.)
BERT goes even one step further. In BERT pre-training a word in a sentence is „masked“, where the model tries to predict the masked word in a sentence. Also „next sentence prediction“ is used to pre-train BERT models. By doing so, BERT has a even better ability to understand semantic relations in a text.