@Robin S Good question, theoretically it's more efficient to hook to an object directly when it suits your need, though I'm not sure if it is in practice... I've not done any tests to measure. When hooking '$pages' it's called a "local" hook because it's local to just that instance named $pages (and the hooks are stored with the instance), whereas when hooking 'Pages', it's called a "static" hook and it keeps track track of it in the WireHooks class, as it would apply to any current or future instance of the Pages class. But there's only ever one instance of Pages (named $pages) so it doesn't matter in this case. https://processwire.com/api/ref/wire/get-hooks/
Another way of saying it: The $pages->addHook('method') and $wire->addHook('Pages::method') are technically different calls in that $pages->addHook('method') is saying "Hook method in JUST THIS instance of Pages" and $wire->addHook('Pages::method') says "hook method in ALL instances of Pages".
While it may not matter in the case of $pages (since only ever one instance), it does matter in cases where there can be multiple instances of the class, such as with the $page class. In that case, you have a choice to make of "do I want to hook JUST THIS $page"...
$page->addHook('method', ...);
...or "do I want to hook ALL Page instances" or "do I want to hook ALL BlogPostPage instances", etc.
$wire->addHook('Page::method', ...);
$wire->addHook('BlogPostPage::method', ...);
What's more efficient about local hooks:
If hooking just a single $page instance (or other type), then the attached hooks disappear when the $page instance does. When hooking all instances of a class, then that hook sticks around for the entire request, or until manually removed.
When a single instance is hooked (local) rather than all instances (static) then ProcessWire only has to consider that hook for the one instance, rather than all instances. So less work. For $pages vs Pages, there's only one of them either way, so it probably doesn't matter much one way or the other in that case.