As @Bergi says in his comment, the window
object is wrapped by something called WindowProxy. Exactly as he says: exotic, proxy-like (and quirky and magic :-). A little more details from the specs:
A WindowProxy is an exotic object that wraps a Window ordinary object, indirecting most operations through to the wrapped object. Each browsing context has an associated WindowProxy object. When the browsing context is navigated, the Window object wrapped by the browsing context's associated WindowProxy object is changed.
The WindowProxy exotic object must use the ordinary internal methods except where it is explicitly specified otherwise below.
That last part about using ordinary internal methods "except where...explicitly specified" is key.
In the EcmaScript 262 standard, it specifies that hasOwnProperty
uses GetOwnProperty
. And getOwnPropertyNames
uses OwnPropertyKeys
. And note that both of these are overridden in WindowProxy
:
7.4.5 [[GetOwnProperty]] ( P )
7.4.10 [[OwnPropertyKeys]] ( )
So the two properties you are using above are both using overridden, non-ordinary methods, rather than the "ordinary internal methods." And hence they are giving unusual results. There is even a warning under under 7.4.5 GetOwnProperty
, which warns of a "willful violation" of the specs:
This is a willful violation of the JavaScript specification's invariants of the essential internal methods to maintain compatibility with existing Web content. See tc39/ecma262 issue #672 for more information. [JAVASCRIPT]
This StackOverflow Answer gives a little more of the history of how this strange behavior became part of the HTML5
standard.