Как известно, в реальном применении языка JavaScript глобальный объект не бывает единственным: у каждого окна браузера есть свой глобальный объект и своя система глобальных конструкторов, являющихся его полями.
Как правило, это полезно, потому что применение библиотеки
Prototype или иного средства, пополняющего или подменяющего прототип, никак не влияет на аналогичные объекты в других окнах. Баги не распространяются слишком широко (на несколько окон), злодейские приложения не имеют возможности для внедрения в конфиденциальные структуры данных, и так далее.
Тем не менее, такое разделение имеет свою цену, и зачастую она может представляться излишнею. В частности, простая проверка
value instanceof Array не способна сгодиться для проверки того, является ли некоторое переданное значение массивом, если оно было передано из другого контекста, в котором другое значение
Array. (Подробнее об этом можно прочесть в статье «
Determining with absolute accuracy whether or not ...», например.)
Одним из способов преодоления этого недостатка является создание специальных функций — таких, как метод
Array.isArray, появившийся в ECMAScript 5. Этот способ, впрочем, никак не помогает в изменении поведения тех библиотек исходного кода, которые были ранее сочинены без учёта возможной разницы контекстов и без употребления новых функций ECMAScript.
Вторым способом (возможно, даже более очевидным) является замена глобальных объектов одного контекста на глобальные объекты другого контекста. Как-то так:
- Object = otherContext.Object;
- Array = otherContext.Array;
- и так далее…
К сожалению, приходится видеть, что эквивалентности
({}).constructor === Objectи
[].constructor === Array после такой замены оказываются нарушены.
Существует ли способ восстановить их, чтобы простые конструкции
{…} и
[…] продолжили работать, но порождали объекты и массивы заимствованного контекста?