Может кто-нибудь объяснить этот метод Javascript? - PullRequest
24 голосов
/ 14 февраля 2010

Оригинальный источник: http://twitter.com/tobeytailor/status/8998006366

(x=[].reverse)() === window // true

Я заметил, что это поведение влияет на все нативные типы. Что именно здесь происходит?

1 Ответ

40 голосов
/ 14 февраля 2010

Это связано со странным образом 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. В теории это все еще может потерпеть неудачу, потому что:

  1. window разрешено быть «хост-объектом», а не «нативным объектом»; в этом случае гарантии того, что вы можете передать другим методам прототипов, не обязательно применяются; и
  2. если окно действительно имеет фреймы / фреймы, оно будет пытаться изменить их порядок, что не сработает, потому что коллекция фреймов доступна только для чтения.

Тем не менее, в текущих браузерах первый случай работает, а второй работает без сбоев без ошибок, поэтому вы по-прежнему получаете поведение ===window, а не исключение.

...