JavaScript. Подробное руководство, 6-е издание, стр. 255

<b>function handler(event) {</b>

<b>  event = event || window.event;</b>

<b>  // Здесь находится реализация обработчика</b>

<b>}</b>

Объект события передается обработчикам событий, зарегистрированным с помощью метода

<b>attachEvent(),</b>
но они также могут использовать переменную
<b>window.event</b>
.

В разделе 17.2.2 говорилось, что при регистрации обработчика события посредством HTML-атрибута броузер преобразует строку с программным кодом на языке JavaScript в функцию. Броузеры, отличные от IE, создают функцию с единственным аргументом

<b>event</b>
. В IE создается функция, не принимающая аргументов. Если в таких функциях использовать идентификатор
<b>event</b>
, он будет ссылаться на
<b>window.event</b>
. В любом случае обработчики событий, определяемые в разметке HTML, могут ссылаться на объект события, используя идентификатор
<b>event</b>
.

17.3.2. Контекст обработчиков событий

Когда обработчик событий регистрируется установкой свойства, это выглядит как определение нового метода элемента документа:

<b>e.onclick = function() { /* реализация обработчика */ };</b>

Поэтому нет ничего удивительного, что обработчики событий вызываются (с одним исключением, касающимся IE, которое описывается ниже) как методы объектов, в которых они определены. То есть в теле обработчика событий ключевое слово

<b>this</b>
ссылается на цель события.

В обработчиках ключевое слово

<b>this</b>
ссылается на целевой объект, даже когда они были зарегистрированы с помощью метода
<b>addEventListener().</b>
Однако, к сожалению, это не относится к методу
<b>attachEvent()</b>
: обработчики, зарегистрированные с помощью метода
<b>attachEvent(),</b>
вызываются как функции, и в них ключевое слово
<b>this</b>
ссылается на глобальный (
<b>Window</b>
) объект. Эту проблему можно решить следующим способом:

<b>/*</b>

<b>* Регистрирует указанную функцию как обработчик событий указанного типа в указанном</b>

<b>* объекте. Гарантирует, что обработчик всегда будет вызываться как метод целевого объекта.</b>

<b>*/</b>

<b>function addEvent(target, type, handler) {</b>

<b>  if (target.addEventListener)</b>

<b>    target.addEventListener(type, handler, false);</b>

<b>  else</b>

<b>    target.attachEvent(“on&quot; + type,</b>

<b>      function(event) {</b>

<b>        // Вызвать обработчик как метод цели,</b>

<b>        // и передать ему объект события</b>

<b>        return handler.call(target, event);</b>

<b>    });</b>

<b>}</b>

Обратите внимание, что обработчики событий, зарегистрированные таким способом, нельзя удалить, потому что ссылка на функцию-обертку, передаваемую методу

<b>attachEvent(),</b>
нигде не сохраняется, чтобы ее можно было передать методу
<b>detachEvent()</b>
.

17.3.3. Область видимости обработчика событий

Подобно всем функциям в языке JavaScript, обработчики событий имеют лексическую область видимости. Они выполняются в той области видимости, в какой были определены, а не в той, где они были вызваны, и имеют доступ ко всем локальным переменным в этой области видимости. (Это, например, демонстрируется в функции

<b>addEvent(),</b>
представленной выше.)

Особый случай представляют обработчики событий, которые регистрируются посредством HTML-атрибутов. Они преобразуются в функции верхнего уровня, которые не имеют доступа ни к каким локальным переменным - только к глобальным. Но по историческим причинам они выполняются в модифицированной цепочке областей видимости. Обработчики событий, определяемые посредством HTML-атрибутов, могут использовать свойства целевого объекта, объемлющего элемента

<b>&lt;form&gt;</b>
(если таковой имеется) и объекта
<b>Document</b>
, как если бы они были локальными переменными. В разделе 17.2.2 было показано, как из HTML-атрибута создается функция обработчика события, программный код в которой использует цепочку областей видимости, модифицированную с помощью инструкций
<b>with</b>
.

HTML-атрибуты плохо подходят для включения длинных строк программного кода, и такая модифицированная цепочка областей видимости помогает сократить его. Она позволяет использовать

<b>tagName</b>
вместо
<b>this.tagName</b>
,
<b>getElementByld</b>
вместо
<b>document.getElementByld</b>
, а в обработчиках, привязанных к элементам документа внутри элемента
<b>&lt;form&gt;,</b>
можно ссылаться на другие элементы формы по значению атрибута
<b>id</b>
, используя, например, имя
<b>zipcode</b>
вместо
<b>this.form.zipcode</b>
.

С другой стороны, модифицированная цепочка областей видимости обработчика событий, определяемого с помощью HTML-атрибута, может стать источником ошибок, потому что свойства всех объектов в цепочке видимости скрывают одноименные свойства глобального объекта. Например, объект

<b>Document</b>
определяет (редко используемый) метод
<b>ореn(),</b>
поэтому если обработчику событий, созданному с помощью HTML-атрибута, потребуется вызвать метод
<b>ореn()</b>
объекта
<b>Window</b>
, он вынужден будет явно вызывать его как
<b>window.ореn(),</b>
вместо
<b>ореn().</b>
Аналогичная (но более пагубная) проблема наблюдается при работе с формами, потому что имена и значения атрибутов
<b>id</b>
элементов формы определяют свойства во вмещающем элементе формы (раздел 15.9.1). То есть если, к примеру, форма содержит элемент со значением «location» атрибута
<b>id</b>
, все обработчики событий, созданные внутри этой формы с помощью HTML-атрибутов, должны будут использовать
<b>window.location</b>
вместо
<b>location</b>
, если им потребуется сослаться на объект
<b>Location</b>
окна.