The global $post
object exists already for singular views before wp_head
is called. It is just not filled with all data.
The the_title()
calls get_the_title()
which in turn calls get_post()
. And that calls $GLOBALS['post']
if no post ID has been passed.
See also Generating the ogp tags in theme for a use case.