Как говорит @Bergi в своем комментарии, объект window
обернут чем-то, что называется WindowProxy . Точно так, как он говорит: exoti c, proxy-like (и своеобразный и волшебный c :-). Еще немного подробностей из спецификации:
WindowProxy - это объект exoti c, который оборачивает обычный объект Window, направляя большинство операций через обернутый объект. Каждый контекст просмотра имеет связанный объект WindowProxy. При навигации по контексту просмотра объект Window, обернутый связанным с контекстом просмотра объектом WindowProxy, изменяется.
Объект WindowProxy exoti c должен использовать обычные внутренние методы, за исключением случаев, когда это явно указано иначе, ниже.
Последняя часть об использовании обычных внутренних методов «кроме случаев, где явно указано» является ключевой.
В стандарте EcmaScript 262 указано, что hasOwnProperty
использует GetOwnProperty
. И getOwnPropertyNames
использует OwnPropertyKeys
. И обратите внимание, что оба они переопределяются в WindowProxy
:
7.4.5 [[GetOwnProperty]] (P)
7.4.10 [[OwnPropertyKeys]] ()
Итак, два свойства, которые вы используете выше, оба используют переопределенные, необычные методы, а не "обычные внутренние методы". И, следовательно, они дают необычные результаты. Под 7.4.5 GetOwnProperty
есть даже предупреждение, которое предупреждает о «преднамеренном нарушении» спецификаций:
Это преднамеренное нарушение инвариантов спецификации JavaScript основных внутренних методов для поддерживать совместимость с существующим веб-контентом. См. Tc39 / ecma262, выпуск № 672, для получения дополнительной информации. [JAVASCRIPT]
Этот Ответ StackOverflow дает немного больше истории того, как это странное поведение стало частью HTML5
стандарта.