Это связано со странным образом this
привязка работает в JavaScript.
[].reverse
- это метод reverse
в пустом списке. Если вы звоните по одному из номеров:
[].reverse();
[]['reverse']();
([].reverse)();
затем выполняется с this
привязанным к экземпляру списка []
. Но если вы отсоедините его:
x= [].reverse;
x();
выполняется без привязки this
, поэтому this
в функции указывает на глобальный (window
) объект, что является одной из самых страшных и вводящих в заблуждение ошибок проектирования JavaScript.
(x=[].reverse)()
также занимается отделением. Оператор присваивания возвращает тот же объект функции, который был передан, так что похоже, что он ничего не делает, но имеет побочный эффект, заключающийся в нарушении ограниченного специального случая, который заставляет JavaScript связывать this
.
Итак, вы говорите:
Array.prototype.reverse.call(window)
reverse
, как и многие другие Array.prototype
методы, определяется в ECMAScript для работы с любым нативным последовательным объектом. Он переворачивает элементы с помощью числовых ключей (до object.length
) и возвращает объект. Таким образом, он вернет объект, который был передан для любого типа, который имеет свойство length
.
window
имеет свойство длины, которое соответствует window.frames.length
, поэтому вызов этого метода с this
, указывающим на window
, сработает и вернет window
. В теории это все еще может потерпеть неудачу, потому что:
window
разрешено быть «хост-объектом», а не «нативным объектом»; в этом случае гарантии того, что вы можете передать другим методам прототипов, не обязательно применяются; и
- если окно действительно имеет фреймы / фреймы, оно будет пытаться изменить их порядок, что не сработает, потому что коллекция фреймов доступна только для чтения.
Тем не менее, в текущих браузерах первый случай работает, а второй работает без сбоев без ошибок, поэтому вы по-прежнему получаете поведение ===window
, а не исключение.